I have 10 different fragments in my application. I need to hide Navigation drawer (Drawer Layout) in few fragments, how can I access Drawer Layout from a fragment and hide it? I know we need to use in activity mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED); but how to do it in fragments?
You could do something like this in your Fragment:
private MainActivity main;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
main = (MainActivity) activity;
}
You definitely should avoid this!
A mutch better solution would be to use an Interface to communicate between your Main and the Fragment. You will end up with something like this:
public interface MyInterface {
public void lockDrawer();
public void unlockDrawer();
}
Main:
public class DetailViewActivity extends AppCompatActivity implements MyInterface {
#Override
public void lockDrawer() {
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
}
#Override
public void unlockDrawer() {
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
}
}
Fragment:
public class MyFragment extends Fragment {
private MyInterface myInterface;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
myInterface = (MyInterface) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement MyInterface");
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
// Inflate the layout for this fragment
myInterface.lockDrawer();
return inflater.inflate(R.layout.example_fragment, container, false);
}
#Override
public void onDestroyView() {
super.onDestroyView();
myInterface.unlockDrawer();
}
}
Why this is the best solution: If you do something like ((HomeActivity) mActivity) you will not be able to reuse your Fragment.
There will be a ClassCastException. In order to reuse your Fragment you should use an Interface instead of casting you MainActivity. So every Activity which will use
your Frament can simply implement this Interface. Even if there's no DrawerLayout you can use it. So the big effort is reusability.
KOTLIN SOLUTION WITH NAVIGATION COMPONENT:
If you use a navigation component (one main activity with multiple fragment destinations) then you need to use addOnDestinationChangedListener to handle which fragment will you show and on which will hide your navigation view inside drawer layout.
Here you can see how to start with the navigation component and here is about the setDrawerLockMode method.
So your code will look something like this:
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
val navController = findNavController(R.id.nav_host_fragment)
navController.addOnDestinationChangedListener{_, destination, _ ->
if (destination.id == R.id.nav_fragment1) {
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED)
//DRAWER LOCKED IN fragment1
} else if (destination.id == R.id.nav_fragment2) {
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED)
//DRAWER UNLOCKED IN fragment2
} else {.....
}
}
This part of the code you can put in the onCreate() method in your MainActivity.
The easiest way to make a Navigation Drawer Activity is automatically in your android studio. Just follow File -> New -> Activity -> Navigation Drawer Activity.
You can do this by following way -
Write one public method inside your activity as follows -
public void enableDisableDrawer(int mode) {
if (mDrawerLayout != null) {
mDrawerLayout.setDrawerLockMode(mode);
}
}
and then inside fragment's onResume you can call this and change Drawer lock mode as required -
((HomeActivity) mActivity).enableDisableDrawer(DrawerLayout.LOCK_MODE_UNLOCKED);
OR
((HomeActivity) mActivity).enableDisableDrawer(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
where mActivity is my activity reference.
This way is working for me.
You can use this method to lock or unlock the drawer: DrawerLayout.setDrawerLockMode(...). (There are also two other versions of this method to specify a lock mode for specific drawers.) To lock, use DrawerLayout.LOCK_MODE_LOCKED_CLOSED; to unlock, use DrawerLayout.LOCK_MODE_UNLOCKED.
If you are using the ActionBarDrawerToggle, you need to add some extra code to prevent the drawer from opening when they click the ActionBarDrawerToggle if you've locked the drawer.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// check lock mode before passing to ActionBarDrawerToggle
// I assume your drawer is on the left; if not, use Gravity.RIGHT
int lockMode = mDrawer.getDrawerLockMode(Gravity.LEFT);
if (lockMode == DrawerLayout.LOCK_MODE_UNLOCKED &&
mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
// Handle your other action bar items...
return super.onOptionsItemSelected(item);
}
refer link for more infolink here
Create two methods in your activity. One for opening the drawer and other for closing it. See below code.
public class MainActivity extends AppCompatActivity {
private DrawerLayout mDrawerLayout;
.......
#Override
protected void onCreate(Bundle savedInstanceState) {
.........
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
.........
}
public void openNavigationDrawer() {
mDrawerLayout.openDrawer(Gravity.LEFT);
}
public void closeNavigationDrawer() {
mDrawerLayout.closeDrawer(Gravity.LEFT);
}
public void lockNavigationDrawer() {
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
}
public void unLockNavigationDrawer() {
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
}
}
Now call the above methods from your fragment like below
((MainActivity)getActivity()).closeNavigationDrawer(); // to close drawer
((MainActivity)getActivity()).openNavigationDrawer(); // to open drawer
((MainActivity)getActivity()).lockNavigationDrawer(); // to lock drawer
((MainActivity)getActivity()).unLockNavigationDrawer(); // to unlock drawer
You can use this method to lock or unlock the drawer: DrawerLayout.setDrawerLockMode(...). (There are also two other versions of this method to specify a lock mode for specific drawers.) To lock, use DrawerLayout.LOCK_MODE_LOCKED_CLOSED; to unlock, use DrawerLayout.LOCK_MODE_UNLOCKED.
If you are using the ActionBarDrawerToggle, you need to add some extra code to prevent the drawer from opening when they click the ActionBarDrawerToggle if you've locked the drawer.
enter code here
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// check lock mode before passing to ActionBarDrawerToggle
// I assume your drawer is on the left; if not, use Gravity.RIGHT
int lockMode = mDrawer.getDrawerLockMode(Gravity.LEFT);
if (lockMode == DrawerLayout.LOCK_MODE_UNLOCKED &&
mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
// Handle your other action bar items...
return super.onOptionsItemSelected(item);
}
I struggled with it for hours: setting DrawerLayout to lock mode simply didn't work for me. Even following your examples.
Finally I came up with this post
DrawerLayout.setDrawerLockMode won't work if you set layout_gravity e.g. to start|bottom in the NavigationView. Just set it to start or end
Hope this helps someone
Related
I am trying to implement behavior of opening bottom sheet when clicked on overflow menu. ex: expected behavior
I may do this on an activity using onMenuOpened as suggested here,
But I want to do this on fragment.
How to achieve this behavior on a fragment?
I am using single activity pattern and navigation architecture component.
Create a interface which will be implemented by your Fragment's
ex:
public interface OnMenuOpenListener(){
boolean onMenuOpened();
}
public class MyFragment extends Fragment implements OnMenuOpenListener{
#Override
public boolean onMenuOpened(){
//open bottom sheet here
}
}
public class MyActivity extends Activity{
#Override
public boolean onMenuOpened(int featureId, Menu menu) {
if(featureId == AppCompatDelegate.FEATURE_SUPPORT_ACTION_BAR && menu != null){
//overflow menu clicked, put code here...
// As you are using navigation component
Fragment navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host);
//MyFragment
Fragment fragment=navHostFragment.getChildFragmentManager().getFragments().get(0);
if(fragment instanceof OnMenuOpenListener){
((OnMenuOpenListener)fragment).onMenuOpened()
return false;
}
}
return super.onMenuOpened(featureId, menu);
}
}
As Support Action Bar is attached to Activity All the event's are captured by Activity all you need to do is get the Fragment which need's the event and trigger the call using a call back.If you return false onMenuOpened will not open the overflow menu and will trigger bottom sheet menu from your fragment.
P.S- I have not written the code in Editor so might have some error's but you must have got the idea.
Reference:
https://stackoverflow.com/a/51732378/7972699
As discussed here opening bottom sheet when clicked on the overflow menu is bad UX.
Why?
Quoting from the post
Because user have to reach the top of the screen to click the oveflow
menu, then go back to the bottom to click desired action which is on
the bottom sheet.
-
According to Fitt's Law - The time to acquire a target is a function
of the distance to and size of the target. I agree that I think
distance between the menu and the bottom sheet is substantial. This
solution allows placing a lot options in one place.
-
it also doesn't match the user expectation since people are used to
the overflow menu opening in a different manner.
If you have a top action bar, use usual context menu. If you have a bottom action bar you may use bottom sheet.
**You can try the following steps to open bottom sheet dialog:**
1. Just make a function inside Activity where the fragment is replace
public Fragment getCurrentFragment() {
return getSupportFragmentManager().findFragmentById(R.id.frameContainer);
}
Fragment fragment = getCurrentFragment();
if (fragment != null) {
if (fragment instanceof RequiredFragment) {
RequiredFragment.openBottumSheetDialog();
}
}
2. In Side RequiredFragment get your function from activity:
private BottomSheetDialog mBottomSheetDialogFragment;
private void showBottomSheetFilter() {
if (mBottomSheetDialogFragment == null) {
mBottomSheetDialogFragment = mBottomSheetDialogFragment.newInstance(feedSection);
mBottomSheetDialogFragment.setCallBackListener(new OnFeedsTypeSelectedListener() {
#Override
public void onFeedsTypeSelected(int contentType) {
filterByContentTypeId(contentType);
}
}
mBottomSheetDialogFragment.show(getChildFragmentManager(),
mBottomSheetDialogFragment.getTag());
}
3. Create a BottomSheetDialog Dialog fragment.
public class BottomSheetDialog extends BottomSheetDialogFragment {
private String[] feedsFilter;
private ListView listView;
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
feedsFilter = getResources().getStringArray(R.array.ideas_filter);
}
#Override
public void setupDialog(final Dialog dialog, int style) {
super.setupDialog(dialog, style);
View contentView = View.inflate(getContext(), R.layout.dialog_idea_filter_bottom_sheet, null);
dialog.setContentView(contentView);
listView = (ListView) contentView.findViewById(R.id.listView);
ArrayAdapter < String > adapter = new ArrayAdapter < String > (getActivity(),
android.R.layout.simple_list_item_1, feedsFilter);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView < ? > parent, View view,
int position, long id) {
if (onFeedsTypeSelected != null) {
onIdeaTypeSelectedListenonFeedsTypeSelecteder.onFeedsTypeSelected(feedsFilter[position]);
}
dismiss();
}
});
}
public void setCallBackListener(onFeedsTypeSelected SelectedListener onFeedsTypeSelected) {
this.onIdeaTypeSelectedLionFeedsTypeSelectedstener = onFeedsTypeSelected;
}
}
I am using a single activity and multiple fragments(screenshot attached) within the same activity to provide a seamless navigation. But after implementing the latest toolbar and navigation view, it seems hard to handle the navigation and home buttons. I am having trouble with the following things.
Managing the Hamburger/Back button at left top. Toggling the icon and functionality to Menu and Back nav.
Page title - Changing the page titles whenever a fragment in pushed and popped.
I have tried several things like overriding onBackPressed(), setHomeAsUpIndicator, popping fragments manually. Earlier i was using ActionBarDrawer toggle to handle this but it is failing somehow now. I checked the google samples they seem to use separate activities at most of the places.
Can anyone guide me how to implement a proper back navigation to handle the NavigationView, Back button in inner fragments and page titles? I am using AppCompatActivity, android.app.Fragment, NavigationView and Toolbar.
It's much easier to illustrate with some sort of division of responsibility for your Activity and Fragment.
Problem 1: Managing the Hamburger/Back button at left top. Toggling the icon and functionality to Menu and Back nav.
From the illustration, the solution should be encapsulated by the Activity, which will look something like this:
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
private ActionBarDrawerToggle mDrawerToggle;
private DrawerLayout mDrawer;
private ActionBar mActionBar;
private boolean mToolBarNavigationListenerIsRegistered = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
mActionBar = getSupportActionBar();
mDrawer = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
mDrawer.addDrawerListener(mDrawerToggle);
mDrawerToggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
// On orientation change savedInstanceState will not be null.
// Use this to show hamburger or up icon based on fragment back stack.
if(savedInstanceState != null){
resolveUpButtonWithFragmentStack();
} else {
// You probably want to add your ListFragment here.
}
}
#Override
public void onBackPressed() {
if (mDrawer.isDrawerOpen(GravityCompat.START)) {
mDrawer.closeDrawer(GravityCompat.START);
} else {
int backStackCount = getSupportFragmentManager().getBackStackEntryCount();
if (backStackCount >= 1) {
getSupportFragmentManager().popBackStack();
// Change to hamburger icon if at bottom of stack
if(backStackCount == 1){
showUpButton(false);
}
} else {
super.onBackPressed();
}
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
} else if (id == android.R.id.home) {
// Home/Up logic handled by onBackPressed implementation
onBackPressed();
}
return super.onOptionsItemSelected(item);
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
// Navigation drawer item selection logic goes here
mDrawer.closeDrawer(GravityCompat.START);
return true;
}
private void replaceFragment() {
/**
* Your fragment replacement logic goes here
* e.g.
* FragmentTransaction ft = getFragmentManager().beginTransaction();
* String tag = "MyFragment";
* ft.replace(R.id.content, MyFragment.newInstance(tag), tag).addToBackStack(null).commit();
*/
// The part that changes the hamburger icon to the up icon
showUpButton(true);
}
private void resolveUpButtonWithFragmentStack() {
showUpButton(getSupportFragmentManager().getBackStackEntryCount() > 0);
}
private void showUpButton(boolean show) {
// To keep states of ActionBar and ActionBarDrawerToggle synchronized,
// when you enable on one, you disable on the other.
// And as you may notice, the order for this operation is disable first, then enable - VERY VERY IMPORTANT.
if(show) {
// Remove hamburger
mDrawerToggle.setDrawerIndicatorEnabled(false);
// Show back button
mActionBar.setDisplayHomeAsUpEnabled(true);
// when DrawerToggle is disabled i.e. setDrawerIndicatorEnabled(false), navigation icon
// clicks are disabled i.e. the UP button will not work.
// We need to add a listener, as in below, so DrawerToggle will forward
// click events to this listener.
if(!mToolBarNavigationListenerIsRegistered) {
mDrawerToggle.setToolbarNavigationClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onBackPressed();
}
});
mToolBarNavigationListenerIsRegistered = true;
}
} else {
// Remove back button
mActionBar.setDisplayHomeAsUpEnabled(false);
// Show hamburger
mDrawerToggle.setDrawerIndicatorEnabled(true);
// Remove the/any drawer toggle listener
mDrawerToggle.setToolbarNavigationClickListener(null);
mToolBarNavigationListenerIsRegistered = false;
}
// So, one may think "Hmm why not simplify to:
// .....
// getSupportActionBar().setDisplayHomeAsUpEnabled(enable);
// mDrawer.setDrawerIndicatorEnabled(!enable);
// ......
// To re-iterate, the order in which you enable and disable views IS important #dontSimplify.
}
}
Problem 2: Page title - Changing the page titles whenever a fragment in pushed and popped.
Essentially, this can be handled in the onStart for each Fragment i.e. your ListFragment, DetailsFragment and CommentsFragment look something like this:
#Override
public void onStart() {
super.onStart();
// where mText is the title you want on your toolbar/actionBar
getActivity().setTitle(mText);
}
Probably worth having setRetainInstance(true) in the onCreate of your fragments as well.
tl;dr
Watch this:
https://youtu.be/ANpBWIT3vlU
Clone this:
https://github.com/shredderskelton/androidtemplate.
This is a really common problem and one that I've overcome by creating a kind of template project which I use whenever I start a new Android project. The idea is to abstract as much of the logic that handles the back button, the 'hamburger' indicator and fragment management into reusable classes:
Start by creating a BaseActivity and BaseFragment class. This is where you are going to as much of the reusable code as possible.
Lets start with your BaseActivity
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
fragmentManager = getSupportFragmentManager();
fragmentHandler = new AddFragmentHandler(fragmentManager);
fragmentManager.addOnBackStackChangedListener(backStackListener);
}
The FragmentManager is the key to owning the back stack, so you need to listen for changes to the back stack from here. The AddFramentHandler is a little class I cooked up to make it easier to add Fragments, from Fragments. More on that later.
#Override
public void onBackPressed() {
if (sendBackPressToDrawer()) {
//the drawer consumed the backpress
return;
}
if (sendBackPressToFragmentOnTop()) {
// fragment on top consumed the back press
return;
}
//let the android system handle the back press, usually by popping the fragment
super.onBackPressed();
//close the activity if back is pressed on the root fragment
if (fragmentManager.getBackStackEntryCount() == 0) {
finish();
}
}
onBackPressed is where most of the magic happens. You notice the plain text formatting of the methods.. I'm a huge Clean Code fan - if you need to write comments, your code isn't clean. Basically you need to really have a central place where you can run to when you're not sure why a back button press is not happening the way you expect. This method is that place.
private void syncDrawerToggleState() {
ActionBarDrawerToggle drawerToggle = getDrawerToggle();
if (getDrawerToggle() == null) {
return;
}
if (fragmentManager.getBackStackEntryCount() > 1) {
drawerToggle.setDrawerIndicatorEnabled(false);
drawerToggle.setToolbarNavigationClickListener(navigationBackPressListener); //pop backstack
} else {
drawerToggle.setDrawerIndicatorEnabled(true);
drawerToggle.setToolbarNavigationClickListener(drawerToggle.getToolbarNavigationClickListener()); //open nav menu drawer
}
}
This is the other key part of the BaseActivity. Basically this method checks whether you are at the root fragment and sets up the indicator accordingly. Notice that it changes the listener depending on how many fragments are in the back stack.
Then there is the BaseFragment:
#Override
public void onResume() {
super.onResume();
getActivity().setTitle(getTitle());
}
protected abstract String getTitle();
The code above shows how the title is handled by the fragments.
Try something like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
if (getSupportActionBar()!=null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
final ActionBarDrawerToggle drawerToggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(drawerToggle);
drawerToggle.syncState();
final View.OnClickListener originalToolbarListener = drawerToggle.getToolbarNavigationClickListener();
final View.OnClickListener navigationBackPressListener = new View.OnClickListener() {
#Override
public void onClick(View v) {
getFragmentManager().popBackStack();
}
};
getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
if (getFragmentManager().getBackStackEntryCount() > 0) {
drawerToggle.setDrawerIndicatorEnabled(false);
drawerToggle.setToolbarNavigationClickListener(navigationBackPressListener);
} else {
drawerToggle.setDrawerIndicatorEnabled(true);
drawerToggle.setToolbarNavigationClickListener(originalToolbarListener);
}
}
});
// Though below steps are not related but I have included to show drawer close on Navigation Item click.
navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem item) {
int id = item.getItemId();
/**
* handle item clicks using id
*/
drawer.closeDrawer(GravityCompat.START);
return true;
}
});
}
Handle the drawer state onBackPressed:
#Override
public void onBackPressed() {
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
To reload previous fragment on back press, always add the fragment transaction to back stack like this:
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction();
SomeFragment fragmentToBeLoaded = new SomeFragment();
fragmentTransaction.replace(R.id.fragment_container, fragmentToBeLoaded,
fragmentToBeLoaded.getName());
fragmentTransaction.addToBackStack(fragmentToBeLoaded.getName());
fragmentTransaction.commit();
To dynamically change the page title, you can call this from every Fragments onStart or onResume method:
#Override
public void onStart() {
super.onStart();
getActivity().setTitle("Title for fragment");
}
Note: I have considered standard layout declaration and thus I have not included any layouts.
"Page title - Changing the page titles whenever a fragment in pushed and popped"
When you remove a fragment, there is the method isRemoving(). It helps to change title back.
#Override
public void onStop() {
super.onStop();
if (isRemoving()) {
// Change your title here
}
}
"functionality to Menu and Back nav"
Suggestion: we have to rely on the default android navigation system. If we use addToBackStack() for our fragments, in theory we don't have to override onBackPressed() at all.
"App does not redefine the expected function of a system icon (such as the Back button)."
"App supports standard system Back button navigation and does not make use of any custom, on-screen "Back button" prompts."
Core App Quality: https://developer.android.com/distribute/essentials/quality/core.html
"Managing the Hamburger/Back button at left top"
I suggest to use activity instead of 'MainActivityDetailFragment' to avoid complication.
Add this in your MainActivity where you are calling Fragments. getBackStackEntryCount() Return number of fragments in the back stack. where the fragment on the bottom of the stack has index 0. popBackStack() Pop the top Fragment off the back stack
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
if (getSupportFragmentManager().getBackStackEntryCount() == 1) {
getSupportFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
return true;
}
And in your Fragment where you want to go back use this function
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == android.R.id.home) {
getActivity().onBackPressed();
}
return true;
}
Ok, after a lot of tests I finally succeeded to setup a good navigation. I needed exactly the same as you, the only difference is that I am using v4 Fragments, but I don't think this will change anything here.
I am not using ActionBarDrawerToggle since the latest examples from Google do not use this component anymore.
The solution below also works for deep navigation: parent activity --> fragment --> fragment etc.
The only change needed in the Fragments is to change the title:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getActivity().setTitle(R.string.targets);
}
In the parent Activity onCreate method, I initialize the following:
mNavigationView = (NavigationView) findViewById(R.id.navigation_view);
setupDrawerContent(mNavigationView);
final Toolbar toolbar = (Toolbar) findViewById(R.id.drawer_toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_menu_24);// Set the hamburger icon
getSupportActionBar().setDisplayHomeAsUpEnabled(true);// Set home button pressable
// Handle the changes on the actionbar
getSupportFragmentManager().addOnBackStackChangedListener(
new FragmentManager.OnBackStackChangedListener() {
public void onBackStackChanged() {
// When no more fragments to remove, we display back the hamburger icon and the original activity title
if (getSupportFragmentManager().getBackStackEntryCount() <= 0) {
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_menu_24);
setTitle(R.string.app_name);
}
// Else displays the back arrow
else {
getSupportActionBar().setHomeAsUpIndicator(R.drawable.ic_arrow_back_24);
}
}
});
Here is now the code to handle the action on the Home button:
#Override
public boolean onOptionsItemSelected(MenuItem item){
// Close the soft keyboard right away
Tools.setSoftKeyboardVisible(mViewPager, false);
switch (item.getItemId()) {
case android.R.id.home:
// When no more fragments to remove, open the navigation drawer
if (getSupportFragmentManager().getBackStackEntryCount() <= 0) {
mDrawerLayout.openDrawer(GravityCompat.START);
}
// Removes the latest fragment
else {
getSupportFragmentManager().popBackStack();
}
return true;
}
return super.onOptionsItemSelected(item);
}
And finally the code to handle the back press action:
#Override
public void onBackPressed() {
// When no more fragments to remove, closes the activity
if (getSupportFragmentManager().getBackStackEntryCount() <= 0) {
super.onBackPressed();
}
// Else removes the latest fragment
else {
getSupportFragmentManager().popBackStack();
}
}
NOTE: I am using an AppCompatActivity, a NavigationView and the theme Theme.AppCompat.Light.NoActionBar.
I'm swapping out the action bar for the tool bar, and I nearly have every piece of the puzzle in place. My issue is specifically if I navigate 'up' and restore the navigation drawer, the drawer toggle button no longer works. I figured out if I set the drawer mode to unlocked I have the ability to swipe to open the drawer, but can't click to open the drawer.
So I load fragment A, drawer behaviour is fine, go down to fragment B and apply the up icon, hit up to go back to A, and the drawer won't open with a click any more.
Entering Fragment B:
Toolbar t = mHostingActivity.getToolbar();
mHostingActivity.getDrawerToggle().setDrawerIndicatorEnabled(false);
mHostingActivity.getSupportActionBar().setDisplayHomeAsUpEnabled(true);
t.setNavigationIcon(mHostingActivity.getV7DrawerToggleDelegate().getThemeUpIndicator());
t.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
popBackStackToTop(mHostingActivity);
}
});
/**
* Pop the back stack and hide the Up caret all the way to the top level of the {#link com.loylap.activities.MainActivity}
*
* #param activity our hosting activity
*/
public static void popBackStackToTop(MainActivity activity) {
if (activity != null) {
FragmentManager fm = activity.getSupportFragmentManager();
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
activity.getDrawerLayout().setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
activity.getDrawerToggle().setDrawerIndicatorEnabled(true);
}
}
The navigation drawer is set up just like the sample, maybe the old way of setting up the options is the issue? For example, I still have this in my activity:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
return super.onOptionsItemSelected(item);
}
EDIT:
Okay so I've narrowed down the issue to the setNavigationOnClickListener(). If I don't set this (and go up via back button) - the drawer behaves correctly. So now the question is how do I correctly allow the user to go 'up', and restore the click listener after to we do go up?
So I've figured out I was creating the wrong click listener. Instead of setNavigationOnClickListener(), I need setToolbarNavigationClickListener() :)
A subtle but important change, now the tool bar is behaving in partnership with the v7 ActionBarDrawerToggle
/**
* Create the Up caret for a lower level fragment {#link com.loylap.activities.MainActivity}
*
* #param activity our hosting activity
*/
public static void createUpButton(final MainActivity activity)
{
ActionBarDrawerToggle toggle = activity.getDrawerToggle();
//Disables onClick toggle listener (onClick)
toggle.setDrawerIndicatorEnabled(false);
toggle.setToolbarNavigationClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
popBackStackToTop(activity);
}
});
Toolbar t = activity.getToolbar();
t.setNavigationIcon(activity.getV7DrawerToggleDelegate().getThemeUpIndicator());
activity.getDrawerLayout().setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
}
In my case it was a matter of order, I needed to first set the toolbar and than set the on click listener. in this order:
//works
setSupportActionBar(myToolbar);
myToolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
openDrawer(view);
}
});
rather than this:
//doesn't work
myToolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
openDrawer(view);
}
});
setSupportActionBar(myToolbar);
Inspired by the solution of Daniel Wilson but you only have to do it once and it is all set.
In my NavigationDrawer's setUp() (or you can do it anywhere you are initialising your ActionBarDrawerToggle instance), I write this code:
mDrawerToggle.setToolbarNavigationClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(!mDrawerToggle.isDrawerIndicatorEnabled()) {
getActivity().onBackPressed();
}
}
});
Now every time android.id.home is pressed and hamburger sign is not shown, the parent activity's onBackPressed() is called.
I think you can't use:
t.setNavigationIcon(mHostingActivity.getV7DrawerToggleDelegate().getThemeUpIndicator());
t.setNavigationOnClickListener(new View.OnClickListener() ...
because it will break your normal navigation drawer behaviour.
Instead try something like this in onCreateOptionsMenu(Menu menu, MenuInflater inflater):
mHostingActivity.getDrawerToggle().setDrawerIndicatorEnabled(false);
mHostingActivity.getDrawerToggle().setHomeAsUpIndicator(mHostingActivity.getV7DrawerToggleDelegate().getThemeUpIndicator());
and then in onOptionsItemSelected
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
popBackStackToTop(mHostingActivity);
return true;
default:
break;
}
return false;
}
PS: don't forget to use setHasOptionsMenu(true); in your fragment onCreateView.
To animate we can use.
ValueAnimator drawerAnimator = ValueAnimator.ofFloat(Constants.HAMBURGER, Constants.BACK);
drawerAnimator.addUpdateListener(drawerAnimationUpdateListener);
drawerAnimator.setDuration(Constants.DRAWER_ANIMATION_DURATION);
drawerAnimator.setInterpolator(new LinearInterpolator());
pass action 0 for HAMBURGER icon and 1 for BACK.
public void updateNavigationDrawer(int action) {
drawerArrowDrawable = actionBarDrawerToggle.getDrawerArrowDrawable();
if (action == Constants.BACK) {
actionBarDrawerToggle.setDrawerIndicatorEnabled(false);
actionBarDrawerToggle.setHomeAsUpIndicator(drawerArrowDrawable);
actionBarDrawerToggle.setToolbarNavigationClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//onBackPress();
}
});
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED););
} else {
actionBarDrawerToggle.setDrawerIndicatorEnabled(true);
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
}
if (drawerArrowDrawable.getProgress() != action) {
if (action == Constants.BACK) {
drawerAnimator.start();
} else {
drawerAnimator.reverse();
}
}
}
I created the app drawer by using the following library:
http://developer.android.com/training/implementing-navigation/nav-drawer.html
I want to show the Navigation Drawer with animation when opening the app.
How can I do that?
Predraw listener, aka the safeway
Here is the predraw listener example. It will literally start the animation as soon as it can which maybe a little too fast. You might want to do a combination of this with a runnable shown second. I will not show the two combined, only separate.
#Override
protected void onCreate(Bundle savedInstanceState) {
...
// Building NavDrawer logic here. Just a method call would be best.
...
ViewTreeObserver vto = drawer.getViewTreeObserver();
if (vto != null) vto.addOnPreDrawListener(new ShouldShowListener(drawer));
}
private static class ShouldShowListener implements OnPreDrawListener {
private final DrawerLayout drawerLayout;
private ShouldShowListener(DrawerLayout drawerLayout) {
this.drawerLayout= drawerLayout;
}
#Override
public boolean onPreDraw() {
if (view != null) {
ViewTreeObserver vto = view.getViewTreeObserver();
if (vto != null) {
vto.removeOnPreDrawListener(this);
}
}
drawerLayout.openDrawer(Gravity.LEFT);
return true;
}
}
PostDelay Runnable, aka living dangerous
// Delay is in milliseconds
static final int DRAWER_DELAY = 200;
#Override
protected void onCreate(Bundle savedInstanceState) {
...
// Building NavDrawer logic here. Just a method call would be best.
...
new Handler().postDelayed(openDrawerRunnable(), DRAWER_DELAY);
}
private Runnable openDrawerRunnable() {
return new Runnable() {
#Override
public void run() {
drawerLayout.openDrawer(Gravity.LEFT);
}
}
}
WARNING
If they rotate on the start of the app for the first time BOOM! Read this blog post for more information http://corner.squareup.com/2013/12/android-main-thread-2.html. Best thing to do would be to use the predraw listener or remove your runnable in onPause.
You can call openDrawer(int gravity) on the DrawerLayout to make it open the drawer with an animation.
You need to call drawerLayout.openDrawer(Gravity.LEFT) to animate the drawer opening. The drawer won't animate if you make the call too early in the Activity lifecycle.
The simplest solution is to just set a flag in onCreate() and act on it in onResume().
You want to make sure that you only set the flag when savedInstanceState is null indicating that the Activity isn't being resumed from the background. You don't want the drawer sliding out every time you change orientation or switch applications.
public class MainActivity extends ActionBarActivity {
private DrawerLayout drawerLayout;
private boolean firstResume = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
drawerLayout = (DrawerLayout)findViewById(R.id.drawer);
if(savedInstanceState == null){
firstResume = true;
}
}
#Override
protected void onResume() {
super.onResume();
if(firstResume) {
drawerLayout.openDrawer(Gravity.LEFT);
}
firstResume = false;
}
}
You could also use an OnPreDrawListener but I feel it's a bit unnecessarily complicated as onPreDraw is called multiple times so you need to remove the listener after opening the drawer. You're also assuming that preDraw is a suitable time to activate the drawer which is an internal implementation of the drawer layout. A future implementation might not animate properly until after onDraw for example.
Delaying the drawer opening by an arbitrary number of milliseconds is a dangerous way to solve this problem. In the worst case the call to open the drawer could happen after onDestroy if the user navigates away quickly.
When using the Navigation Drawer the Android devs are recommending that in the ActionBar "only those screens that are represented in the Navigation Drawer should actually have the Navigation Drawer image" and that "all other screens have the traditional up carat."
See here for details: http://youtu.be/F5COhlbpIbY
I'm using one activity to control multiple levels of fragments and can get the Navigation Drawer image to display and function at all levels.
When creating lower level fragments I can call the ActionBarDrawerToggle setDrawerIndicatorEnabled(false) to hide the Navigation Drawer image and have the Up caret displayed
LowerLevelFragment lowFrag = new LowerLevelFragment();
//disable the toggle menu and show up carat
theDrawerToggle.setDrawerIndicatorEnabled(false);
getSupportFragmentManager().beginTransaction().replace(R.id.frag_layout,
lowFrag, "lowerFrag").addToBackStack(null).commit();
The problem I'm having is when I navigate back to the top level fragments the Up carat still shows instead of the original Navigation Drawer image. Any suggestions on how to "refresh" the ActionBar on the top level fragments to re-display the Navigation Drawer image?
Solution
Tom's suggestion worked for me. Here’s what I did:
MainActivity
This activity controls all fragments in the app.
When preparing new fragments to replace others, I set the DrawerToggle setDrawerIndicatorEnabled(false) like this:
LowerLevelFragment lowFrag = new LowerLevelFragment();
//disable the toggle menu and show up carat
theDrawerToggle.setDrawerIndicatorEnabled(false);
getSupportFragmentManager().beginTransaction().replace(R.id.frag_layout,
lowFrag).addToBackStack(null).commit();
Next, in an override of onBackPressed, I reverted the above by setting the DrawerToggle to setDrawerIndicatorEnabled(true) like this:
#Override
public void onBackPressed() {
super.onBackPressed();
// turn on the Navigation Drawer image;
// this is called in the LowerLevelFragments
setDrawerIndicatorEnabled(true)
}
In the LowerLevelFragments
In the fragments I modified onCreate and onOptionsItemSelected like this:
In onCreate added setHasOptionsMenu(true) to enable configuring the options menu. Also set setDisplayHomeAsUpEnabled(true) to enable the < in the actionbar:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// needed to indicate that the fragment would
// like to add items to the Options Menu
setHasOptionsMenu(true);
// update the actionbar to show the up carat/affordance
getActivity().getActionBar().setDisplayHomeAsUpEnabled(true);
}
Then in onOptionsItemSelected whenever the < is pressed it calls the onBackPressed() from the activity to move up one level in the hierarchy and display the Navigation Drawer Image:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Get item selected and deal with it
switch (item.getItemId()) {
case android.R.id.home:
//called when the up affordance/carat in actionbar is pressed
getActivity().onBackPressed();
return true;
…
}
It's easy as 1-2-3.
If you want to achieve:
1) Drawer Indicator - when no fragments are in the Back Stack or the Drawer is opened
2) Arrow - when some Fragments are in the Back Stack
private FragmentManager.OnBackStackChangedListener
mOnBackStackChangedListener = new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
syncActionBarArrowState();
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
mDrawerToggle = new ActionBarDrawerToggle(
this,
mDrawerLayout,
R.drawable.ic_navigation_drawer,
0,
0
) {
public void onDrawerClosed(View view) {
syncActionBarArrowState();
}
public void onDrawerOpened(View drawerView) {
mDrawerToggle.setDrawerIndicatorEnabled(true);
}
};
mDrawerLayout.setDrawerListener(mDrawerToggle);
getSupportFragmentManager().addOnBackStackChangedListener(mOnBackStackChangedListener);
}
#Override
protected void onDestroy() {
getSupportFragmentManager().removeOnBackStackChangedListener(mOnBackStackChangedListener);
super.onDestroy();
}
private void syncActionBarArrowState() {
int backStackEntryCount =
getSupportFragmentManager().getBackStackEntryCount();
mDrawerToggle.setDrawerIndicatorEnabled(backStackEntryCount == 0);
}
3) Both indicators to act according to their shape
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mDrawerToggle.isDrawerIndicatorEnabled() &&
mDrawerToggle.onOptionsItemSelected(item)) {
return true;
} else if (item.getItemId() == android.R.id.home &&
getSupportFragmentManager().popBackStackImmediate()) {
return true;
} else {
return super.onOptionsItemSelected(item);
}
}
P.S. See Creating a Navigation Drawer on Android Developers on other tips about the 3-lines indicator behavior.
You have written that, to implement lower-level fragments, you are replacing the existing fragment, as opposed to implementing the lower-level fragment in a new activity.
I would think that you would then have to implement the back functionality manually: when the user pressed back you have code that pops the stack (e.g. in Activity::onBackPressed override). So, wherever you do that, you can reverse the setDrawerIndicatorEnabled.
I've used next thing:
getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
if(getSupportFragmentManager().getBackStackEntryCount() > 0){
mDrawerToggle.setDrawerIndicatorEnabled(false);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
else {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
mDrawerToggle.setDrawerIndicatorEnabled(true);
}
}
});
If your up action bar button doesn't work, don't forget to add the listener :
// Navigation back icon listener
mDrawerToggle.setToolbarNavigationClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onBackPressed();
}
});
I've got some trouble implementing a drawer navigation with a home button, everything worked except the action buton.
Try handling the Home item selection in the MainActivity depending on the state of the DrawerToggle. This way you don't have to add same code to every fragment.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Only handle with DrawerToggle if the drawer indicator is enabled.
if (mDrawerToggle.isDrawerIndicatorEnabled() &&
mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
// Handle action buttons
switch (item.getItemId()) {
// Handle home button in non-drawer mode
case android.R.id.home:
onBackPressed();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
FOLLOW UP
The solution given by #dzeikei is neat, but it can be extended, when using fragments, to automatically handle setting back the drawer indicator when the backstack is empty.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Only handle with DrawerToggle if the drawer indicator is enabled.
if (mDrawerToggle.isDrawerIndicatorEnabled() &&
mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
// Handle action buttons
switch (item.getItemId()) {
// Handle home button in non-drawer mode
case android.R.id.home:
// Use getSupportFragmentManager() to support older devices
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.popBackStack();
// Make sure transactions are finished before reading backstack count
fragmentManager.executePendingTransactions();
if (fragmentManager.getBackStackEntryCount() < 1){
mDrawerToggle.setDrawerIndicatorEnabled(true);
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
EDIT
For the question of #JJD.
The fragments are held/managed in an activity. The above code is written once in that activity, but only handle the up caret for the onOptionsItemSelected.
In one of my apps I also needed to handle the behavior of the up caret when the back button was pressed. This can be handle by overriding onBackPressed.
#Override
public void onBackPressed() {
// Use getSupportFragmentManager() to support older devices
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.executePendingTransactions();
if (fragmentManager.getBackStackEntryCount() < 1){
super.onBackPressed();
} else {
fragmentManager.executePendingTransactions();
fragmentManager.popBackStack();
fragmentManager.executePendingTransactions();
if (fragmentManager.getBackStackEntryCount() < 1){
mDrawerToggle.setDrawerIndicatorEnabled(true);
}
}
};
Note the code duplication between onOptionsItemSelected and onBackPressed which can be avoided by creating a method and calling that method in both places.
Also note I add two more times executePendingTransactions which in my case was required or else I had sometimes strange behaviors of the up caret.
I created an interface for the hosting activity to update the view state of the hamburger menu. For top level fragments I set the toggle to true and for fragments for which I want to display the up < arrow I set the toggle to false.
public class SomeFragment extends Fragment {
public interface OnFragmentInteractionListener {
public void showDrawerToggle(boolean showDrawerToggle);
}
private OnFragmentInteractionListener mListener;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
this.mListener = (OnFragmentInteractionListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnFragmentInteractionListener");
}
}
#Override
public void onResume() {
super.onResume();
mListener.showDrawerToggle(false);
}
}
Then in my Activity ...
public class MainActivity extends Activity implements SomeFragment.OnFragmentInteractionListener {
private ActionBarDrawerToggle mDrawerToggle;
public void showDrawerToggle(boolean showDrawerIndicator) {
mDrawerToggle.setDrawerIndicatorEnabled(showDrawerIndicator);
}
}
This answer was working but there was a little problem with it.
The getSupportActionBar().setDisplayHomeAsUpEnabled(false) was not called explicitly and it was causing drawer icon to be hidden even when there were no items in the backstack so changing the setActionBarArrowDependingOnFragmentsBackStack() method worked for me.
private void setActionBarArrowDependingOnFragmentsBackStack() {
int backStackEntryCount = getSupportFragmentManager()
.getBackStackEntryCount();
// If there are no items in the back stack
if (backStackEntryCount == 0) {
// Please make sure that UP CARAT is Hidden otherwise Drawer icon
// wont display
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
// Display the Drawer Icon
mDrawerToggle.setDrawerIndicatorEnabled(true);
} else {
// Show the Up carat
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// Hide the Drawer Icon
mDrawerToggle.setDrawerIndicatorEnabled(false);
}
}
Logic is clear.
Show back button if fragment back stack is clear.
Show material hamburger-back animation if fragment stack is not clear.
getSupportFragmentManager().addOnBackStackChangedListener(
new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
syncActionBarArrowState();
}
}
);
private void syncActionBarArrowState() {
int backStackEntryCount = getSupportFragmentManager().getBackStackEntryCount();
mNavigationDrawerFragment.setDrawerIndicatorEnabled(backStackEntryCount == 0);
}
//add these in Your NavigationDrawer fragment class
public void setDrawerIndicatorEnabled(boolean flag){
ActionBar actionBar = getActionBar();
if (!flag) {
mDrawerToggle.setDrawerIndicatorEnabled(false);
actionBar.setDisplayHomeAsUpEnabled(true);
mDrawerToggle.setHomeAsUpIndicator(getColoredArrow());
} else {
mDrawerToggle.setDrawerIndicatorEnabled(true);
}
mDrawerToggle.syncState();
getActivity().supportInvalidateOptionsMenu();
}
//download back button from this(https://www.google.com/design/icons/) website and add to your project
private Drawable getColoredArrow() {
Drawable arrowDrawable = ContextCompat.getDrawable(getActivity(), R.drawable.ic_arrow_back_black_24dp);
Drawable wrapped = DrawableCompat.wrap(arrowDrawable);
if (arrowDrawable != null && wrapped != null) {
// This should avoid tinting all the arrows
arrowDrawable.mutate();
DrawableCompat.setTint(wrapped, Color.GRAY);
}
return wrapped;
}
If you take a look at the GMAIL app and come here to search for the carret/affordance icon..
I would ask you to do this, none of the above answer was clear. i was able to modify the accepted answer.
NavigationDrawer --> Listview contains subfragments.
subfragments will be listed like this
firstFragment == position 0 ---> this will have subfragments --> fragment
secondFragment
thirdFragment and so forth....
In firstFragment you have other fragment.
Call this on DrawerActivity
getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
if (getFragmentManager().getBackStackEntryCount() > 0) {
mDrawerToggle.setDrawerIndicatorEnabled(false);
} else {
mDrawerToggle.setDrawerIndicatorEnabled(true);
}
}
});
and in fragment
setHasOptionsMenu(true);
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Get item selected and deal with it
switch (item.getItemId()) {
case android.R.id.home:
//called when the up affordance/carat in actionbar is pressed
activity.onBackPressed();
return true;
}
return false;
}
On the OnBackPressed Drawer activity method set the drawer toggle to true to enable navigation list icon again.
Thanks,
Pusp
You can look at this little example!
https://github.com/oskarko/NavDrawerExample
IMO, using onNavigateUp() (as shown here) in riwnodennyk's or Tom's solution is cleaner and seems to work better. Just replace the onOptionsItemSelected code with this:
#Override
public boolean onSupportNavigateUp() {
if (getSupportFragmentManager().getBackStackEntryCount() > 0) {
// handle up navigation
return true;
} else {
return super.onSupportNavigateUp();
}
}