Once, my drawer icon changed from hamburger to the back button calling this:
((AppCompatActivity)getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
So, the back arrow is shown, but clicking on it , the drawer is still opening.
I would like to be able to handle it, to call onBackpressed() instead.
This is when i make the instance of the drawer
mActionBarDrawerToggle = new ActionBarDrawerToggle(getActivity(), mDrawerLayout, toolbar, R.string.drawer_open, R.string.drawer_close) {
#Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
if (!isAdded()) return;
getActivity().invalidateOptionsMenu();
}
#Override
public View.OnClickListener getToolbarNavigationClickListener() {
return super.getToolbarNavigationClickListener();
}
#Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
if (!isAdded()) return;
if (!mUserLearnedDrawer) {
mUserLearnedDrawer = true;
saveSharedSetting(getActivity(), PREF_USER_LEARNED_DRAWER, "true");
}
getActivity().invalidateOptionsMenu();
}
};
I suppose that getToolbarNavigationClickListener() method must be called when I tap on the drawer toogle, no matter if its hamburger or back arrow, but it does not.
When you need to override Arrow on toolbar click, set navigation click to toolbar.
getSupportActionBar().setNavigationOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
//handle back press or open drawer etc.
}
});
It works for me every time.
Related
I'm currently struggling with the DrawerLayout animation doing weird stuff; The hamburger icon is laggy and often switch from hamburger to arrow without animation if I don't put an Handler to delay the fragment transaction animation.
So I ended up putting an handler to wait until the hamburger icon perform the animation but it just doesn't feel natural that we need to wait until the drawer close to switch fragment. I'm sure there is a better way to handle this...
Here is how I do currently:
private void selectProfilFragment() {
final BackHandledFragment fragment;
// TODO test this again
Bundle bundle = new Bundle();
bundle.putString(FragmentUserProfile.USER_FIRST_NAME, user.getFirstname());
bundle.putString(FragmentUserProfile.USER_LAST_NAME, user.getLastname());
bundle.putString(FragmentUserProfile.USER_PICTURE, user.getProfilepic());
bundle.putString(FragmentUserProfile.USER_EMAIL, user.getEmail());
bundle.putBoolean(FragmentUserProfile.USER_SECURITY, user.getParameters().getSecuritymodule().equals("YES"));
fragment = new FragmentUserProfile();
fragment.setArguments(bundle);
mDrawerLayout.closeDrawer(mDrawerLinear);
new Handler().postDelayed(new Runnable() {
public void run() {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.setCustomAnimations(R.anim.pull_in_right, R.anim.push_out_left, R.anim.pull_in_left, R.anim.push_out_right);
ft.replace(R.id.content_frame, fragment)
.addToBackStack(fragment.getTagText())
.commitAllowingStateLoss();
}
}, 300);
}
It's still glitching a little bit in between the DrawerLayout closing and opening fragment transaction animation.
Here is How I instanciate the drawer:
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
mDrawerListChild.setAdapter(new DrawerListAdapter(this, R.layout.drawer_layout_item, mPlanTitles));
mDrawerListChild.setOnItemClickListener(new DrawerItemClickListener());
mProfilPic.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
selectProfilFragment();
}
});
mDrawerToggle = new ActionBarDrawerToggle(
this,
mDrawerLayout,
toolbar,
R.string.drawer_open,
R.string.drawer_close
) {
public void onDrawerClosed(View view) {
invalidateOptionsMenu();
}
public void onDrawerOpened(View drawerView) {
invalidateOptionsMenu();
}
};
getSupportFragmentManager().addOnBackStackChangedListener(mOnBackStackChangedListener);
mDrawerLayout.setDrawerListener(mDrawerToggle);
setSupportActionBar(toolbar);
I am not sure what causing this behavior though I want to draw your attention on few thing.
I am not aware which ActionBarDrawerToggle class you are using but preferable to use android.support.v7.app.ActionBarDrawerToggle instead of android.support.v4.app.ActionBarDrawerToggle as it is deprecated.
Use addDrawerListener() instead of setDrawerListener() as it is deprecated.
Use spinBars and set value true to rotate bars during transition.
e.x. in your styles.xml as described here.
In onDrawerClosed and onDrawerOpened call syncState(). Also call this method on your ActionBarDrawerToggle. Check this.
Hope this will help you.
Heres how you can do it. In the Activity containing fragment setup your drawer.
public void setupDrawer(){
NavigationFragment drawerFragment = (NavigationFragment)
getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
mActionbarToggle = drawerFragment.setUp(R.id.navigation_drawer, mDrawerLayout, mToolbar);
}
Now in the NavigationDrawerFragment define your setUp method
public ActionBarDrawerToggle setUp(int navigation_drawer, DrawerLayout drawerLayout, Toolbar mToolbar) {
mFragmentContainerView = getActivity().findViewById(navigation_drawer);
this.mDrawerLayout = drawerLayout;
//mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
ActionBar actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeButtonEnabled(true);
mDrawerToggle = new ActionBarDrawerToggle(getActivity(), drawerLayout, mToolbar, R.string.drawer_open, R.string.drawer_close) {
#Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
if (!isAdded()) {
return;
}
getActivity().supportInvalidateOptionsMenu(); // calls onPrepareOptionsMenu()
}
#Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
if (!isAdded()) {
return;
}
getActivity().supportInvalidateOptionsMenu(); // calls onPrepareOptionsMenu()
}
};
mDrawerToggle.setToolbarNavigationClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((MainActivity) mContext).onBackPress();
}
});
mDrawerLayout.post(new Runnable() {
#Override
public void run() {
mDrawerToggle.syncState();
}
});
mDrawerLayout.setDrawerListener(mDrawerToggle);
return mDrawerToggle;
}
That's it, your drawer is completely setUp.
I have a drawerLayout (support.v4) with a navigationView and have many (like many up to n menu items) menu items. To have less items on the screen at the same time, some menu items lead to another menu with many items.
The thing is, my menu switch works fine, I'm able to pass from one menu to the other one but I have no animation... I want to close the drawer when an item linked to another menu is selected and once the menu is loaded, to open it again.
Here's my code:
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem selectedItem) {
mDrawerLayout.closeDrawer(GravityCompat.START);
Log.d(MainActivity.class.getName(), selectedItem.toString());
MobileXMLMenu menu = UserMenu.getInstance().getMenu();
for(int i = 0; i < menu.sizeMenuItems(); i++){
if(menu.getMenuItem(i).getLabel(Utility.retreiveLanguage()).equals(selectedItem.toString())){
Log.d(MainActivity.class.getName(), menu.getMenuItem(i).sizeMenuItems() + "");
if(menu.getMenuItem(i).sizeMenuItems() > 0){
Menu nMenu = navigationView.getMenu();
nMenu.clear();
for(int j = 0; j < menu.getMenuItem(i).sizeMenuItems(); j++){
MobileXMLMenuItem item = menu.getMenuItem(i).getMenuItem(j);
nMenu.add(item.getLabel(Utility.retreiveLanguage())).setIcon(MemberOptionsManager.getInstance().getMenuItemIcon(item.getDecorator()));
}
mDrawerLayout.openDrawer(GravityCompat.START);
isInSubmenu = true;
}
}
}
return false;
}
});
I also have this for my ActionBarDrawerToggle (don't know if this could help):
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, mToolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close){
public void onDrawerClosed(View view){
super.onDrawerClosed(view);
getSupportActionBar().setTitle(mFragment.getFragmentName());
invalidateOptionsMenu();
mDrawerToggle.syncState();
}
public void onDrawerOpened(View drawerView){
super.onDrawerClosed(drawerView);
getSupportActionBar().setTitle("Open");
invalidateOptionsMenu();
mDrawerToggle.syncState();
}
};
When I select an item not link to any sub menu, the drawer closes, but otherwise, I see no animation, just the menu content changing with no animation. How can I force my app to wait for the drawer to close before changing the menu content?
Thanks!
You can use callback methods of the drawer layout from official documentation of the android.
onDrawerClosed(View drawerView)
onDrawerOpened(View drawerView)
onDrawerSlide(View drawerView, float slideOffset)
onDrawerStateChanged(int newState)
You can find more at link:http://developer.android.com/reference/android/support/v4/widget/DrawerLayout.DrawerListener.html
You can setDrawerListener on DrawLayout like this
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, mDrawerLayout, mToolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close) {
public void onDrawerClosed(View view) {
handleClickNavigationItem(mClickedNavigationItem);
}
public void onDrawerOpened(View drawerView) {
}
};
mDrawerLayout.setDrawerListener(toggle);
handleClickNavigationItem method contains the code which handle navigation event.
And just save clicked item in onNavigationItemSelected method
public boolean onNavigationItemSelected(MenuItem item) {
mClickedNavigationItem = item.getItemId();
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
I have a toolbar with the "back button" on the left side and a button to to open the navigation drawer fragment on the right side. Now, if I click on the button on the right side and then on the back button on the left side, the app crashed and said : "No drawer view found with gravity LEFT". Yeah the fragment is on the right side and the question is how can I avoid this? Here is my code:
in OnCreate:
setSupportActionBar(toolbarTutorial);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
in onOptionsItemSelected:
if (id == R.id.editInformations) {
drawerLayout.setDrawerListener(new ActionBarDrawerToggle(ProfileActivity.this,
drawerLayout, toolbarTutorial, R.string.drawer_open,R.string.drawer_close){
#Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
mSlideState = false;
}
#Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
mSlideState = true;
}
});
clickEventSlide();
}
and the clickEventSlide method:
public void clickEventSlide(){
if(mSlideState){
drawerLayout.closeDrawer(Gravity.END);
}else{
drawerLayout.openDrawer(Gravity.END);
}}
It is possible to just show the Android default hamburger navigation drawer without change to back arrow feature?
The animation you're referring to is handled in the onDrawerOpened(), onDrawerClosed(), and onDrawerSlide() methods of the ActionBarDrawerToggle class. To disable it, simply override those methods without calling through to the super's methods. For example:
ActionBarDrawerToggle drawerToggle = new ActionBarDrawerToggle(...) {
#Override
public void onDrawerClosed(View drawerView) {
}
#Override
public void onDrawerOpened(View drawerView) {
}
#Override
public void onDrawerSlide(View drawerView, float slideOffset) {
}
};
I had standart navigation drawer, but now i'm trying to modify it, using toolbar.
Earlier my code looked like:
MainActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.v("MAIN", "CREATE");
initViews();
setListeners();
getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
shouldDisplayHomeUp();
}
});
mNavigationDrawerFragment = (NavigationDrawerFragment)
getFragmentManager().findFragmentById(R.id.navigation_drawer);
mTitle = getTitle();
// Set up the drawer.
mNavigationDrawerFragment.setUp(
R.id.navigation_drawer,
(DrawerLayout) findViewById(R.id.drawer_layout));
}
NavigationDrawerFragment.java
public void setUp(int fragmentId, DrawerLayout drawerLayout) {
mFragmentContainerView = getActivity().findViewById(fragmentId);
mDrawerLayout = drawerLayout;
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
((MainActivity) getActivity()).getSupportActionBar().setDisplayHomeAsUpEnabled(true);
((MainActivity) getActivity()).getSupportActionBar().setHomeButtonEnabled(true);
mDrawerToggle = new ActionBarDrawerToggle(getActivity(), mDrawerLayout,
((MainActivity) getActivity()).getToolbar(),
R.string.navigation_drawer_open,
R.string.navigation_drawer_close) {
#Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
if (!isAdded()) {
return;
}
getActivity().invalidateOptionsMenu(); // calls onPrepareOptionsMenu()
}
#Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
if (!isAdded()) {
return;
}
if (!mUserLearnedDrawer) {
// The user manually opened the drawer; store this flag to prevent auto-showing
// the navigation drawer automatically in the future.
mUserLearnedDrawer = true;
SharedPreferences sp = PreferenceManager
.getDefaultSharedPreferences(getActivity());
sp.edit().putBoolean(PREF_USER_LEARNED_DRAWER, true).apply();
}
if (mDrawerListView != null) {
}
getActivity().invalidateOptionsMenu(); // calls onPrepareOptionsMenu()
}
#Override
public void onDrawerSlide(View drawerView, float slideOffset) {
super.onDrawerSlide(drawerView, slideOffset);
}
};
// If the user hasn't 'learned' about the drawer, open it to introduce them to the drawer,
// per the navigation drawer design guidelines.
if (!mUserLearnedDrawer && !mFromSavedInstanceState) {
mDrawerLayout.openDrawer(mFragmentContainerView);
}
// Defer code dependent on restoration of previous instance state.
mDrawerToggle.setDrawerIndicatorEnabled(true);
mDrawerLayout.post(new Runnable() {
#Override
public void run() {
mDrawerToggle.syncState();
}
});
mDrawerLayout.setDrawerListener(mDrawerToggle);
}
Now i modified my code:
MainActivity.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mToolbar = (Toolbar) findViewById(R.id.toolbar);
if (mToolbar != null) {
setSupportActionBar(mToolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
initViews();
setListeners();
mNavigationDrawerFragment = (NavigationDrawerFragment)
getFragmentManager().findFragmentById(R.id.navigation_drawer);
mTitle = getTitle();
// Set up the drawer.
mNavigationDrawerFragment.setUp(
R.id.navigation_drawer,
(DrawerLayout) findViewById(R.id.drawer_layout));
shouldDisplayHomeUp();
getFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
mBackCount++;
shouldDisplayHomeUp();
}
});
}
NavigationDrawerFragment.java
public void setUp(int fragmentId, DrawerLayout drawerLayout) {
mFragmentContainerView = getActivity().findViewById(fragmentId);
mDrawerLayout = drawerLayout;
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
mDrawerToggle = new ActionBarDrawerToggle(getActivity(), mDrawerLayout,
((MainActivity) getActivity()).getToolbar(),
R.string.navigation_drawer_open,
R.string.navigation_drawer_close) {
#Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
if (!isAdded()) {
return;
}
getActivity().invalidateOptionsMenu(); // calls onPrepareOptionsMenu()
}
#Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
if (!isAdded()) {
return;
}
if (!mUserLearnedDrawer) {
// The user manually opened the drawer; store this flag to prevent auto-showing
// the navigation drawer automatically in the future.
mUserLearnedDrawer = true;
SharedPreferences sp = PreferenceManager
.getDefaultSharedPreferences(getActivity());
sp.edit().putBoolean(PREF_USER_LEARNED_DRAWER, true).apply();
}
if (mDrawerListView != null) {
}
getActivity().invalidateOptionsMenu(); // calls onPrepareOptionsMenu()
}
#Override
public void onDrawerSlide(View drawerView, float slideOffset) {
super.onDrawerSlide(drawerView, slideOffset);
}
};
// If the user hasn't 'learned' about the drawer, open it to introduce them to the drawer,
// per the navigation drawer design guidelines.
if (!mUserLearnedDrawer && !mFromSavedInstanceState) {
mDrawerLayout.openDrawer(mFragmentContainerView);
}
// Defer code dependent on restoration of previous instance state.
mDrawerToggle.setDrawerIndicatorEnabled(true);
mDrawerLayout.post(new Runnable() {
#Override
public void run() {
mDrawerToggle.syncState();
}
});
mDrawerLayout.setDrawerListener(mDrawerToggle);
}
And shouldDisplayHomeUp function:
public void shouldDisplayHomeUp (){
boolean canBack = getFragmentManager().getBackStackEntryCount() > 0;
mNavigationDrawerFragment.getDrawerToggle().setDrawerIndicatorEnabled(!canBack);
}
But the back arrow is not shown
I tried call
getSupportActionBar().setDisplayHomeAsUpEnabled(canBack);
getSupportActionBar().setHomeButtonEnabled(canBack);
So the back arrow appers but clicking on it has no effect
From the docs:
To allow Up navigation with the app icon in the action bar, call
setDisplayHomeAsUpEnabled():
#Override public void onCreate(Bundle savedInstanceState) {
...
getActionBar().setDisplayHomeAsUpEnabled(true); }
This adds a left-facing caret alongside the app icon and enables it as an action
button such that when the user presses it, your activity receives a
call to onOptionsItemSelected(). The ID for the action is
android.R.id.home.
This means that you will have to implement your back routine on onOptionsItemSelected and check for R.id.home. To avoid calling the routine when you click on the hamburger menu check for canback too on onOptionsItemSelected.
http://developer.android.com/training/implementing-navigation/ancestral.html#up
EDIT
To archieve what you want you will have to implement your own navigation routine.
mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(shouldBack()) {
//call onbackpressed or something
if(displayBackAgain)
return; //return after so you don't call syncState();
}else if (mNavigationDrawerFragment.isDrawerOpen())
mNavigationDrawerFragment.closeDrawer();
else
mNavigationDrawerFragment.openDrawer();
mNavigationDrawerFragment.getActionBarDrawerToggle().syncState();
}
});
}
To enable the backbutton icon just call getSupportActionBar().setDisplayHomeAsUpEnabled(true); to disable it just call mNavigationDrawerFragment.getActionBarDrawerToggle().syncState();
I found a way to control the back button and the nav. It worked with me.
First , set up:
private void setupNav () {
this.toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(this.toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
this.mActionBarDrawerToggle = new ActionBarDrawerToggle(this, this.mDrawerLayout, this.toolbar, 0, 0);
this.mActionBarDrawerToggle.setToolbarNavigationClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//catch back button here.
}
});
this.mDrawerLayout.setDrawerListener(this.mActionBarDrawerToggle);
this.mActionBarDrawerToggle.syncState();
}
Important thing, this is the way I hide the hamburger and show the back button. You have to put this code in the place you want to show back button. I also lock the Nav when showing back button.
if (!isShowBackButton) {
mActionBarDrawerToggle.setDrawerIndicatorEnabled(true);
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
} else {
mActionBarDrawerToggle.setDrawerIndicatorEnabled(false);
mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
//enable back button
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}