handle DrawerLayout in fragments - java

I am trying to debug an app built with fragments. Since I don't know nearly anything about fragments, I have some problems with them.
I want the action button to be transformed in back button when I open a fragment from MainActivity or another fragment.
I kinda made that work, but when I press back from a fragment and it resumes the other the back button transforms back to home button.
I want to know how I can make that home button behave like the back button on Android when it transforms to the back arrow. It does nothing currently.
Here is some code I think it's relevant, I will provide more if you need:
MainActivity
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_trash_all:
DataHolder.cart = null;
isTrashButtonPresent = false;
supportInvalidateOptionsMenu();
inflateFragment(CartFragment.newInstance(null, null));
resolveCircularText(DataHolder.getOverallCartQuantity());
return true;
case R.id.btnMyMenu:
if (drawer.getDrawerLockMode(GravityCompat.START)
==DrawerLayout.LOCK_MODE_LOCKED_CLOSED) {
onBackPressed();
} else {
drawerToggle();
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void drawerToggle() {
if (drawer.isDrawerVisible(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
drawer.openDrawer(GravityCompat.START);
}
}
private void setupNavigationDrawer() {
mDrawerToggle = new ActionBarDrawerToggle(
this, drawer, toolbar,
R.string.navigation_drawer_open,R.string.navigation_drawer_close);
mDrawerToggle.setHomeAsUpIndicator(R.drawable.drawer_icon);
drawer.addDrawerListener(mDrawerToggle);
navigationView.setNavigationItemSelectedListener(this);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
}
setDrawerState(true);
}
public void setDrawerState(boolean isEnabled) {
if (isEnabled) {
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED,
GravityCompat.START);
mDrawerToggle.syncState();
} else {
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED,
GravityCompat.START);
//Drawable backButton = ContextCompat.getDrawable(this,
R.mipmap.ic_back_button);
getSupportActionBar().setHomeAsUpIndicator(null);
}
}
Fragments:
OnCreate:
if (getActivity() != null) {
((MainActivity) getActivity()).setDrawerState(false);
}
#Override
public void onDestroy() {
super.onDestroy();
if (getActivity() != null) {
((MainActivity) getActivity()).setDrawerState(true);
}
}
Thank you in advance!

Try using Interface class:
public interface DrawerViewInterface {
void lockDrawer();
void unlockDrawer();
void showBackIcon();
void showHamburgerIcon();
}
Now, Implement this Interface class in your MainActivity:
public class MainActivity extends AppCompactActivity implements DrawerViewInterface {
#Override
public void lockDrawer() {
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
}
#Override
public void unlockDrawer() {
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
}
#Override
public void showBackIcon() {
mActionBarDrawerToggle.setDrawerIndicatorEnabled(false);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
#Override
public void showHamburgerIcon() {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
mActionBarDrawerToggle.setDrawerIndicatorEnabled(true);
}
}
Now, In your Fragment, call whatever you want by:
((DrawerViewInterface) getActivity()).showHamburgerIcon();
or
((DrawerViewInter) getActivity()).showBackIcon();

Related

Change BottomNavigationView Icons on Back Button clicked

At the bottom of my layout I have a BottomNavigationView with three fragments. If I click the back button the fragment is switching but not the bottom icons. How can I fix it?
addToBackStack() works. Maybe you have some advise to pretty the code. Is it good practise to have the fragment tags in the activity or fragment?
public class MainActivity extends AppCompatActivity {
private FragmentManager mFragmentManager;
private BottomNavigationView mBottomNavigationView;
private static final String HOME_FRAGMENT = "homeFragment";
private static final String SEARCH_FRAGMENT = "searchFragment";
private static final String SHARE_FRAGMENT = "shareFragment";
private boolean isFirstFragment;
private long mBackPressedTime;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
setBottomNavigationView();
}
private void init() {
mBottomNavigationView = findViewById(R.id.bottomNavigationView);
mFragmentManager = getSupportFragmentManager();
mBackPressedTime = 0;
}
private void setBottomNavigationView() {
setFragment(HomeFragment.newInstance(), HOME_FRAGMENT);
isFirstFragment = true;
mBottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.ic_home:
setFragment(HomeFragment.newInstance(), HOME_FRAGMENT);
return true;
case R.id.ic_search:
setFragment(SearchFragment.newInstance(), SEARCH_FRAGMENT);
return true;
case R.id.ic_circle:
setFragment(ShareFragment.newInstance(), SHARE_FRAGMENT);
return true;
default:
return false;
}
}
});
}
private void setFragment(Fragment fragment, String tag) {
FragmentTransaction transaction = mFragmentManager.beginTransaction();
transaction.replace(R.id.container, fragment, tag);
if (isFirstFragment) {
transaction.addToBackStack(tag);
}
transaction.commit();
}
#Override
public void onBackPressed() {
final long currentTimeMillis = System.currentTimeMillis();
if (mFragmentManager.getBackStackEntryCount() > 0) {
mFragmentManager.popBackStack();
} else if (currentTimeMillis - mBackPressedTime > 2000) {
mBackPressedTime = currentTimeMillis;
Toast.makeText(this, getString(R.string.reach_homescreen), Toast.LENGTH_SHORT).show();
} else {
super.onBackPressed();
}
}
}
#Hans Baum instead of adding your first fragment to back stack try this code,
#Override
public void onBackPressed() {
if(mBottomNavigationView.getSelectedItemId () != R.id.ic_home)
{
mBottomNavigationView.setSelectedItemId(R.id.ic_home);
}
else
{
super.onBackPressed();
}
}
This code will exit your activity if you are in Home Fragment else if you are in any other Fragment it will go to Home Fragment.
So no addToBackStack() needed. So your serFragment() method should be,
private void setFragment(Fragment fragment, String tag) {
FragmentTransaction transaction = mFragmentManager.beginTransaction();
transaction.replace(R.id.container, fragment, tag);
transaction.commit();
}
hope it helps.
Note that in your code you never assigned false to isFirstFragment so i assume all fragments are added to backstack which is very memory consuming.
UPDATE:
Since your requirement is different.As you want Instagram like tabs, i hope this implementation helps you .
Deque<Integer> mStack = new ArrayDeque<>();
boolean isBackPressed = false;
private void setBottomNavigationView() {
mBottomNavigationView.setOnNavigationItemSelectedListener(new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.ic_home:
if(!isBackPressed) {
pushFragmentIntoStack(R.id.ic_home);
}
isBackPressed = false
setFragment(HomeFragment.newInstance(), HOME_FRAGMENT);
return true;
case R.id.ic_search:
if(!isBackPressed) {
pushFragmentIntoStack(R.id.ic_search);
}
isBackPressed = false
setFragment(SearchFragment.newInstance(), SEARCH_FRAGMENT);
return true;
case R.id.ic_circle:
if(!isBackPressed) {
pushFragmentIntoStack(R.id.ic_circle);
}
isBackPressed = false
setFragment(ShareFragment.newInstance(), SHARE_FRAGMENT);
return true;
default:
return false;
}
}
});
mBottomNavigationView.setOnNavigationItemReselectedListener(new
BottomNavigationView.OnNavigationItemReselectedListener() {
#Override
public void onNavigationItemReselected(#NonNull MenuItem item) {
}
});
mBottomNavigationView.setSelectedItemId(R.id.ic_home);
pushFragmentIntoStack(R.id.ic_home);
}
private void pushFragmentIntoStack(int id)
{
if(mStack.size() < 3)
{
mStack.push(id);
}
else
{
mStack.removeLast();
mStack.push(id);
}
}
private void setFragment(Fragment fragment, String tag) {
FragmentTransaction transaction = mFragmentManager.beginTransaction();
transaction.replace(R.id.container, fragment, tag);
transaction.commit();
}
#Override
public void onBackPressed() {
if(mStack.size() > 1)
{
isBackPressed = true;
mStack.pop();
mBottomNavigationView.setSelectedItemId(mStack.peek());
}
else
{
super.onBackPressed();
}
}
I have used deque to store the order in which the tabs are clicked Since there are 3 tabs deque size is 3 .On back press it will pop the stack and go to that tab. If no item in stack it will quit the activity.
IMPORTANT NOTE:
Do not add fragments to backstack in this scenario because as i switch the tabs the backstack count will keep increasing and may even lead to MemoryOutOfBound exception.
To Question 2:
Coming to your Fragment tag question , It is good to save tag in fragment . As the fragment is reusable in any activity instead adding tag in every activity it is used , it is good if we add it in fragment itself.
Try this:
#Override
public void onBackPressed() {
if(navigation_bottom.getSelectedItemId () != R.id.action_home)
{
FragmentTransaction transaction =
((HomeActivity)this).getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.frameLayout_home, new HomeFragment());
transaction.commit();
navigation_bottom.setSelectedItemId(R.id.action_home);
}
else
{
HomeActivity.this.finishAffinity();
}
}
You can add the fragment name in the backstack with the fragment transaction
getFragmentManager()
.beginTransaction()
.replace(R.id.frame, YourCurrentFragment.newInstance())
.addToBackStack(YourFragment.class.getName())
.commit();
Then you can add onBackstackChangedListener to get the currently selected fragment
fragmentManager.addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
FragmentManager.BackStackEntry bse = fragmentManager.
getBackStackEntryAt(fragmentManager.getBackStackEntryCount() -1);
//bse will be the backstack entry for current fragment
if (bse.getName().equals(YourFragment.class.getName())) {
navigationView.getMenu().getItem(0).setChecked(true);
} else if (bse.getName().equals(YourSecondFragment.class.getName())) {
navigationView.getMenu().getItem(1).setChecked(true);
}
}
});

Set Toolbar Home Navigation Button to Follow backstack, Android

I have set up a toolbar and added a home navigation button as follows;
Toolbar toolbar;
toolbar = (Toolbar) findViewById(R.id.toolbar_home);
//Setup toolbar
toolbar.setTitle("Home");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
toolbar.setTitleTextColor(getResources().getColor(R.color.icons,null));
}else{
toolbar.setTitleTextColor(getResources().getColor(R.color.icons));
}
setSupportActionBar(toolbar);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
} else {
Log.w("Home", "toolbar null");
}
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Navigate backwards as android back button
}
});
I want when i press the toolbar backbutton, it navigates backwards following the backstack as the the android backbutton.enter image description here
add this method in activity:
#Override
public boolean onOptionsItemSelected(MenuItem item)
{
if(item.getItemId() == android.R.id.home){
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
I am following this from long time and not found any issue yet .
HomeFragment : First fragment which getting loaded first time
getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
HomeFragment currentHomeFragment = null;
currentHomeFragment = (HomeFragment) getFragmentManager().findFragmentByTag("HOME_FRAGMENT");
if (currentHomeFragment != null && currentHomeFragment.isVisible()) {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
toggle.syncState();
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
drawer.openDrawer(GravityCompat.START);
}
});
} else {
if (getFragmentManager().getBackStackEntryCount() > 1) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true); // show back button
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getFragmentManager().popBackStackImmediate();
}
});
} else {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
toggle.syncState();
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
drawer.openDrawer(GravityCompat.START);
}
});
}
}
}
});
If you are using android.support.v7.widget.Toolbar add this code to your AppCompatActivity:
#Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
in your onClick write onBackPressed(); or in manifest
<activity android:name=".XYZActivity"
android:parentActivityName=".MainActivity" />
Setup toolbar in MainActivity onCreate() method.
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar_home);
toolbar.setTitle("Activity Name");
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
Setup back navigation by implementing below method in MainActivity Level.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
Works well..
#Rajesh

Android BaseFragment class with multiple different fragment types

I created a base fragment class that handles setting the toolbar title, registering for when the fragment is attached, setting the menu icons and a few other things. My issue is that I've decided to use the PreferencesFragmentCompat for my settings fragment and I cant extend both my BaseFragment and androids PreferencesFragmentCompat. Using an interface here wouldn't help because my BaseFragment has a lot of functionality, and I don't want to duplicate it into each of my fragment classes. Normally to extend two classes, you just do it in two seperate files but because both already extend off Androids Fragment class, I dont see how this is possible. Is there a better way of doing this?
BaseFragment:
public abstract class BaseFragment extends Fragment {
protected View rootView;
protected AppSettings settings;
protected LayoutInflater inflater;
public static void startFragment(Activity activity, BaseFragment newFragment) {
FragmentManager fragManager = ((AppCompatActivity) activity).getSupportFragmentManager();
BaseFragment currentFragment = (BaseFragment) fragManager.findFragmentById(R.id.fragment_container);
// Start the transactions
FragmentTransaction transaction = fragManager.beginTransaction();
transaction.replace(R.id.fragment_container, newFragment);
// If there is already a fragment then we want it on the backstack
if (currentFragment != null) {
transaction.addToBackStack(null);
}
// Show it
transaction.commit();
}
#TargetApi(21)
private void lockMode(boolean start) {
if (android.os.Build.VERSION.SDK_INT >= 16) {
if (start) {
getActivity().startLockTask();
} else {
getActivity().stopLockTask();
}
}
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Get a reference to the app settings
settings = AppSettings.getInstance(getActivity());
// Don't want keyboard to stay open between fragments
hideKeyboard();
ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
if (actionBar != null) {
if (toolbarElevation()) {
actionBar.setElevation(4 * getActivity().getResources().getDisplayMetrics().density);
} else {
actionBar.setElevation(0);
}
}
setHasOptionsMenu(true);
}
#Override
public void onResume() {
super.onResume();
// Set the title up
Toolbar toolbar = (Toolbar) getActivity().findViewById(R.id.toolbar);
toolbar.setTitle(getTitle());
// Enable the home button in the action bar
((AppCompatActivity) getActivity()).getSupportActionBar().setDisplayShowHomeEnabled(true);
// Change the home button icon for menu or back
if (showUpNavigation()) {
toolbar.setNavigationIcon(R.drawable.ic_navigation_back_white);
} else {
toolbar.setNavigationIcon(R.drawable.ic_menu_white);
}
if (isAppInLockTaskMode() == true && pinnedMode() == false) {
lockMode(false);
}
setDrawerMenu();
}
public boolean getAuthRequired() {
return true;
}
public boolean isBackAllowed() {
return true;
}
public boolean toolbarElevation() {
return true;
}
public String getTitle() {
return "ISOPED";
}
public boolean pinnedMode() {
return false;
}
public boolean showUpNavigation() {
return false;
}
public void hideKeyboard() {
InputMethodManager inputManager = (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
// check if no view has focus:
View v = getActivity().getCurrentFocus();
if (v == null) {
return;
}
inputManager.hideSoftInputFromWindow(v.getWindowToken(), 0);
}
public void setDrawerMenu() {
NavigationView navigationView = (NavigationView) getActivity().findViewById(R.id.drawer_navigation);
Integer menuID = null;
Integer currentMenuId = null;
if (settings.isType(AppSettings.TYPES.PERSONAL)) {
menuID = R.menu.drawer_personal;
} else if (settings.isType(AppSettings.TYPES.PROFESSIONAL)) {
if (getAuthRequired() == true) {
menuID = R.menu.drawer_professional_locked;
} else {
menuID = R.menu.drawer_professional_unlocked;
}
}
if (menuID != null) {
if (navigationView.getTag() != null) {
currentMenuId = (Integer) navigationView.getTag();
}
if (currentMenuId == null || navigationView.getMenu().size() == 0 || currentMenuId != menuID) {
navigationView.getMenu().clear();
navigationView.inflateMenu(menuID);
navigationView.setTag(Integer.valueOf(menuID));
}
}
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
menu.clear();
if (settings.isType(AppSettings.TYPES.PROFESSIONAL) && pinnedMode() && false == isAppInLockTaskMode()) {
inflater.inflate(R.menu.pin_menu, menu);
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
DrawerLayout drawer = (DrawerLayout) getActivity().findViewById(R.id.drawer_layout);
switch (item.getItemId()) {
case android.R.id.home:
if (showUpNavigation()) {
getActivity().onBackPressed();
} else {
drawer.openDrawer(GravityCompat.START);
}
return true;
case R.id.menu_pin:
if (isAppInLockTaskMode()) {
PinDialog dialog = new PinDialog((AppCompatActivity) getActivity(), new NavigationCallback((AppCompatActivity) getActivity()) {
#Override
public void run() {
lockMode(false);
}
});
dialog.show();
} else {
lockMode(true);
}
return true;
}
return super.onOptionsItemSelected(item);
}
private boolean isAppInLockTaskMode() {
ActivityManager activityManager;
activityManager = (ActivityManager)
getActivity().getSystemService(Context.ACTIVITY_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
// For SDK version 23 and above.
return activityManager.getLockTaskModeState()
!= ActivityManager.LOCK_TASK_MODE_NONE;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
// When SDK version >= 21. This API is deprecated in 23.
return activityManager.isInLockTaskMode();
}
return false;
}
}
This is a nice example, where you should apply Joshua Bloch's "Favor composition over inheritance" idiom.
You can delegate all the logic that you have applied to BaseFragment to some class FragmentHelper:
public class FragmentHelper {
private final Fragment fragment;
public FragmentHelper(Fragment fragment) {
this.fragment = fragment;
}
public void create(Bundle bundle) {
// `BaseFragment`'s code goes here
}
public void resume() {
// `BaseFragment`'s code goes here
}
...
}
Now in your BaseFragment:
public class BaseFragment {
private FragmentHelper fragmentHelper;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
fragmentHelper = new FragmentHelper(this);
fragmentHelper.create(savedInstanceState);
}
#Override
public void onResume() {
fragmentHelper.resume();
}
}
And the same this should be applied to the class that is extending PreferenceFragment.
Thus, you'd evade from code duplication.
Reference:
Joshua Bloch - Effective Java 2nd edition, Item 16.

Back arrow is closing drawer menu, not back

I've got a problem. I've got a hamburger icon and back arrow too. Hamburger is working perfectly, but not the back arrow. It's working like a hamburger, opening and closing drawer menu.
Here is a code:
#Override
public void onDrawerClosed(View drawerView) {
hideKeyboard();
super.onDrawerClosed(drawerView);
}
#Override
public void onDrawerOpened(View drawerView) {
hideKeyboard();
super.onDrawerOpened(drawerView);
}};
mDrawerToggle.setDrawerIndicatorEnabled(true);
mDrawerLayout.setDrawerListener(mDrawerToggle);
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
pager.setVisibility(View.VISIBLE);
tabLayout.setVisibility(View.VISIBLE);
mDrawerToggle.setDrawerIndicatorEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
mDrawerToggle.syncState();
Toolbar toolbar = (Toolbar)findViewById(R.id.toolbarInner);
toolbar.setNavigationOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
openAndCloseDrawer();
}
});
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
openAndCloseDrawer();
return true;
}
return false;
}
});
public void customizeActionBarWithBack(String string)
{
Toolbar toolbar = (Toolbar)findViewById(R.id.toolbarInner);
toolbar.setTitleTextColor(getResources().getColor(R.color.md_white_1000));
toolbar.setTitle(string);
setDisplayHomeAsUpEnabled(true, R.drawable.abc_ic_ab_back_material);
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
toolbar.setNavigationOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
onBackPressed();
customizeActionBar();
}
});
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
#Override
public boolean onMenuItemClick(MenuItem item) {
switch(item.getItemId()) {
case android.R.id.home:
recreate();
customizeActionBar();
return true;
}
return false;
}
});
}
Where is a problem? Please help me guys!
Override onBackPressed and call finish.
#Override
public void onBackPressed()
{
finish();
}
Try this
#Override
public void onBackPressed()
{
mDrawerLayout.closeDrawers();
}
Dawid, you can also do it like as you are implementing navigation drawer in fragment:
#Override
public void onBackPressed() {
int count = getFragmentManager().getBackStackEntryCount();
if (count == 0) {
super.onBackPressed();
//additional code
} else {
getFragmentManager().popBackStack();
}
}
and other option to communicate with activity using interface, implement interface in activity and define it in fragment then u can handle it by callback funtion

Back Button Implementation in Fragment ViewPager

I have 3 Fragments inside a ViewPager. I have different back button functionalities which I want to implement for each Fragment. At the moment, I have created methods in each fragment which correspond to what I want the back button to do. I implemented an interface in my activity with the following methiod:
#Override
public void onCameraBack(int i) {
currFrag = i;
}
The idea here is that there are three fragments, each fragment calls this method in its onStart() method. Fragment 0 passes 0, fragment 1 passes 1 and fragment 2 passes 2. So in this way the holding activity knows which fragment is visible. Now I am trying to get a reference to that fragment to be able to call the backbutton method I have implemented in it. I tried using this :
#Override
public void onBackPressed() {
if (currFrag == 0) {
}
else if (currFrag == 1) {
FragmentBTesting fragmentBTesting= new FragmentBTesting();
fragmentBTesting.FragmentBBack();
}
}`
but this doesn't work. I can't use the findFragmentbyId method since my fragments do not have fragment tags in their XML, they fill the whole screen and their views are defined using linearLayouts. My question is how can I get an instance of the fragment so I can call its FragmentBack() method.
Here is my full activity
public class FragmentActivityTesting extends FragmentActivity implements FragmentATesting.logoutListener,FragmentBTesting.onCameraBack {
ViewPager viewPager = null;
SessionManager session = new SessionManager(MyApp.getContext());
int currFrag;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment_activity_testing);
viewPager = (ViewPager) findViewById(R.id.pic_pager);
setStatusBarColor();
FragmentManager fragmentManager = getSupportFragmentManager();
viewPager.setAdapter(new MyAdapter(fragmentManager));
viewPager.setCurrentItem(1);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("CLOSE_ALL");
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
finish();
}
};
registerReceiver(broadcastReceiver, intentFilter);
}
#TargetApi(21)
public void setStatusBarColor() {
Window window = this.getWindow();
// clear FLAG_TRANSLUCENT_STATUS flag:
window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
// add FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS flag to the window
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
if (Integer.valueOf(android.os.Build.VERSION.SDK) >= 21) {
window.setStatusBarColor(this.getResources().getColor(R.color.green));
}
}
#Override
public void logout() {
session.logOut();
Intent a = new Intent(this,MainActivity.class);
startActivity(a);
Intent intent = new Intent("CLOSE_ALL");
this.sendBroadcast(intent);
finish();
}
#Override
public void onBackPressed() {
if (currFrag == 0) {
}
else if (currFrag == 1) {
FragmentBTesting fragmentBTesting= new FragmentBTesting();
fragmentBTesting.FragmentBBack();
}
}
#Override
public void onCameraBack(int i) {
currFrag = i;
}
}
class MyAdapter extends FragmentStatePagerAdapter {
public MyAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
Fragment fragment = null;
if (position ==0) {
fragment = new FragmentATesting();
}
else if (position == 1) {
fragment = new FragmentBTesting();
}
else if (position == 2) {
fragment = new FragmentCTesting();
}
return fragment;
}
#Override
public int getCount() {
return 3;
}
}
Instead of telling your activity what fragment you are currently on, why not tell it what to execute when back is pressed?
In your activity you can have a field to hold the callback field (as a Runnable, I know so much hate. You can make your own interface if you want), the setter, and then the onBackPressed implementation. Here is a snippet from my code that works. Im using Guava's Optional class, but you can null it instead if you're into that kinda thing.
This is the Activity which should implement ActivityWithHomeButton
private Optional<? extends Runnable> backButtonListener = Optional.absent();
#Override
public void onBackPressed() {
// Check if there is a custom back button
if (backButtonListener.isPresent()) {
backButtonListener.get().run();
backButtonListener = Optional.absent();
} else {
super.onBackPressed();
}
}
#Override
public void setBackButtonListener(Optional<? extends Runnable> backButtonListener) {
this.backButtonListener = backButtonListener;
}
Here is the interface I implement in the activity
public interface ActivityWithHomeButton {
void setBackButtonListener(Optional<? extends Runnable> runnable);
}
and of course the usage from a fragment
parent.setBackButtonListener(Optional.of(new Runnable() {
#Override
public void run() {
// do back button stuff
}
}));
You can put this wherever you want in the fragment. You are also going to want to clear the back button listener whenever you no longer need it (onPause). You can do this as such
parent.setBackButtonListener(Optional.<Runnable>absent());
Where parent can be attained using the standard activity-fragment communication pattern detailed here (http://developer.android.com/training/basics/fragments/communicating.html). This code goes in your fragment
private ActivityWithHomeButton parent;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
parent = (ActivityWithHomeButton) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement ActivityWithHomeButton");
}
}
Hope it helps!

Categories

Resources