I'm trying to implement a Navigation Drawer that hides the menu items in the ActionBar whenever the drawer is opened.
I am following google's documentation, however their code does not produce the expected behavior.
http://developer.android.com/training/implementing-navigation/nav-drawer.html
Using this code, the menu items are hidden when the drawer becomes completely opened , and shown when the drawer becomes completely closed.
However, the Gmail app behaves differently. The menu items are hidden as soon as the drawer opens by any amount. This is the behavior I want. Does anyone know how to achieve this?
Thanks!
Have you tried this:
Use invalidateOptionsMenu() whenever you toggle the nav drawer, by measuring the sliding offset.
Iterate over each menu item in onPrepareOptionsMenu(Menu menu) and hide it.
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
// If the nav drawer is open, hide action items related to the content view
boolean drawerOpen = shouldGoInvisible;
hideMenuItems(menu, !drawerOpen);
return super.onPrepareOptionsMenu(menu);
}
private void hideMenuItems(Menu menu, boolean visible)
{
for(int i = 0; i < menu.size(); i++){
menu.getItem(i).setVisible(visible);
}
}
Detecting how much the nav drawer has slided:
mDrawerLayout.setDrawerListener(new DrawerListener(){
float mPreviousOffset = 0f;
#Override
public void onDrawerClosed(View arg0) {
super.onDrawerClosed(arg0);
shouldGoInvisible = false;
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
#Override
public void onDrawerOpened(View arg0) {
super.onDrawerOpened(arg0);
shouldGoInvisible = true;
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
#Override
public void onDrawerSlide(View arg0, float slideOffset) {
super.onDrawerSlide(arg0, slideOffset);
if(slideOffset > mPreviousOffset && !shouldGoInvisible){
shouldGoInvisible = true;
invalidateOptionsMenu();
}else if(mPreviousOffset > slideOffset && slideOffset < 0.5f && shouldGoInvisible){
shouldGoInvisible = false;
invalidateOptionsMenu();
}
mPreviousOffset = slideOffset;
}
#Override
public void onDrawerStateChanged(int arg0) {
// or use states of the drawer to hide/show the items
}});
Note: shouldGoInvisible is class field.
If you want to override action bar as soon as drawer enters screen and restore action bar the moment drawer is no longer visible (exactly how Gmail behaves as of March 20, 2014) you can use the following code:
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close) {
#Override
public void onDrawerStateChanged(int newState) {
super.onDrawerStateChanged(newState);
boolean isOpened = mDrawerLayout.isDrawerOpen(mDrawerList);
boolean isVisible = mDrawerLayout.isDrawerVisible(mDrawerList);
if (!isOpened && !isVisible) {
if (newState == DrawerLayout.STATE_IDLE) {
// drawer just hid completely
restoreActionBar();
} else {
// } else if (newState == DrawerLayout.STATE_SETTLING) {
// drawer just entered screen
overrideActionBar();
}
}
}
private void restoreActionBar() {
getSupportActionBar().setTitle(mTitle);
supportInvalidateOptionsMenu();
}
private void overrideActionBar() {
getSupportActionBar().setTitle(mDrawerTitle);
supportInvalidateOptionsMenu();
}
};
// Set the drawer toggle as the DrawerListener
mDrawerLayout.setDrawerListener(mDrawerToggle);
Modify restoreActionBar() and overrideActionBar() methods acording to your needs.
There is no need to distinguish between swipes and home button and no need to measure swipe lengths.
Variation
If you don't want to reference the drawer list view use the following code instead:
boolean isOpened = mDrawerLayout.isDrawerOpen(GravityCompat.START);
boolean isVisible = mDrawerLayout.isDrawerVisible(GravityCompat.START);
You may want to use GravityCompat.END instead depending on what you specified in XML layout.
Edit - concerning actions
The above example does not hide action bar items relevant to content below the navigation drawer. To do so or show different set of icons when drawer is visible you have to keep track of whether the drawer is opened or closed manually.
In addition to the above code declare private boolean mDrawerVisible = false with proper save/restore state handling.
Then modify mDrawerToggle inner methods as follows:
private void restoreActionBar() {
getSupportActionBar().setTitle(mTitle);
mDrawerVisible = false;
supportInvalidateOptionsMenu();
}
private void overrideActionBar() {
getSupportActionBar().setTitle(mDrawerTitle);
mDrawerVisible = true;
supportInvalidateOptionsMenu();
}
Finally in onCreateOptionsMenu inflate different menu resource or in onPrepareOptionsMenu show/hide different actions based on the value of mDrawerVisible.
I'd half agree with Nikola but it's sufficient just to update the icons when the drawer state has
Create a global variable to keep track of the drawer state:
private int mDrawerState;
Set a new DrawerListener:
mDrawerLayout.setDrawerListener(new DrawerListener() {
#Override
public void onDrawerStateChanged(int state) {
mDrawerState = state;
invalidateOptionsMenu();
}
#Override
public void onDrawerSlide(View view, float slide) {
// TODO Auto-generated method stub
}
#Override
public void onDrawerOpened(View view) {
// TODO Auto-generated method stub
}
#Override
public void onDrawerClosed(View view) {
// TODO Auto-generated method stub
}
});
Update the menu visibility:
boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawer);
for(int i=0;i<menu.size();i++){
// If the drawer is moving / settling or open do not draw the icons
menu.getItem(i).setVisible(mDrawerState!=DrawerLayout.STATE_DRAGGING &&
mDrawerState!=DrawerLayout.STATE_SETTLING && !drawerOpen);
}
I have a better solution for this question:
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
if (navigationDrawerFragment.isDrawerOpen()) {
menu.clear();
}
return super.onPrepareOptionsMenu(menu);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
if (!navigationDrawerFragment.isDrawerOpen()) {
// Only show items in the action bar relevant to this screen
// if the drawer is not showing. Otherwise, let the drawer
// decide what to show in the action bar.
showLocalContextActionBar();
return false;
}
return super.onCreateOptionsMenu(menu);
}
If you want to hide all menu items, simply use:
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
super.onPrepareOptionsMenu(menu);
return showActionBarMenu; // boolean value, set it in drawer listeners as class variable
}
Then you do not need to visible of each menu item.
I took the answer by #Laurence Dawson and simplified it a bit. This solution does not require any class members to be used.
Execute this code during onCreate():
DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
drawerLayout.setDrawerListener(new DrawerLayout.DrawerListener() {
#Override
public void onDrawerSlide(View view, float v) {
invalidateOptionsMenu();
}
#Override
public void onDrawerClosed(View view) {
invalidateOptionsMenu();
}
#Override
public void onDrawerOpened(View view) {}
#Override
public void onDrawerStateChanged(int state) {}
});
And override this method:
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
boolean actionsVisibility = !drawerLayout.isDrawerVisible(Gravity.START);
for(int i=0;i<menu.size();i++){
menu.getItem(i).setVisible(actionsVisibility);
}
return super.onPrepareOptionsMenu(menu);
}
Few notes:
The above implementation assumes that the view associated with NavigationDrawer has its layout_gravity set to start in XML.
Unrelated to OP's question, but annoying: there seems to be some kind of a bug which causes the drawer to stuck along the way. If you do observe this behavior, here is the solution: Android Navigation Drawer bug using the sample
I have different code but the same solution:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
hideMenuItems(menu, !mShouldGoInvisible);
return super.onCreateOptionsMenu(menu);
}
private void hideMenuItems(Menu menu, boolean visible){
for(int i = 0; i < menu.size(); i++){
menu.getItem(i).setVisible(visible);
}
}
and
#Override
public void onNavigationDrawerListener(boolean opened, int position) {
if (opened){
mShouldGoInvisible = true;
invalidateOptionsMenu();
} else {
mShouldGoInvisible = false;
invalidateOptionsMenu();
}
}
Related
I am using the appcompat activity for Android v-21. I want to enable the home button which I have set it to true in my code. I also have overridden the onOptionsItemSelected but it's still not working.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_apply_card);
mToolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(mToolbar);
//Action bar
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
onBackPressed();
return true;
}
Simple way to add action bar home enable in Appcompat activity
getSupportActionBar().show();
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Add this two pulic functions in your activity also--
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
// app icon in action bar clicked; go home
this.finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
#Override
public void onBackPressed() {
// TODO Auto-generated method stub
super.onBackPressed();
}
Following code snippet set navigation icon in toolbar,
toolbar.setNavigationIcon(R.mipmap.ic_launcher);
I hope it will help you.
I know it is an old question but in order to prevent others to devote their time to solve this issue, I want to share the working method for me.
I am not sure about the reason of this. Probably, since ActionBar is deprecated and gave way to Toolbar after AppCompat, some methods of AppCompatActivity may not work as it is expected. Although the Burger (navigation button) is defined as the home button of ActionBar, we could not control click events of this button by using .onOptionsItemSelected(MenuItem). Toolbar view presents us another method to achieve this, toolbar.setNavigationOnClickListener(View.OnClickListener).
To exemplify, I tried to use balysv's MaterialMenuIcon with this method instead of .onOptionsItemSelected(MenuItem) as follows:
private void setupToolbar() {
toolbar = (Toolbar) ((LinearLayout) findViewById(R.id.app_bar)).getChildAt(0);
setSupportActionBar(toolbar);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (drawerLayout.isDrawerVisible(GravityCompat.START)) {
drawerLayout.closeDrawer(GravityCompat.START);
materialMenu.animatePressedState(MaterialMenuDrawable.IconState.BURGER);
} else {
drawerLayout.openDrawer(GravityCompat.START);
materialMenu.animatePressedState(MaterialMenuDrawable.IconState.ARROW);
}
}
});
materialMenu = new MaterialMenuIconToolbar(this, Color.WHITE, MaterialMenuDrawable.Stroke.THIN) {
#Override public int getToolbarViewId() {
return R.id.toolbar;
}
};
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
drawerLayout.setDrawerListener(new DrawerLayout.SimpleDrawerListener() {
#Override
public void onDrawerSlide(View drawerView, float slideOffset) {
super.onDrawerSlide(drawerView, slideOffset);
materialMenu.setTransformationOffset(
MaterialMenuDrawable.AnimationState.BURGER_ARROW,
isDrawerOpened ? 2 - slideOffset : slideOffset
);
}
#Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
isDrawerOpened = true;
}
#Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
isDrawerOpened = false;
}
#Override
public void onDrawerStateChanged(int newState) {
super.onDrawerStateChanged(newState);
if (newState == DrawerLayout.STATE_IDLE) {
if (isDrawerOpened) materialMenu.setState(MaterialMenuDrawable.IconState.ARROW);
else materialMenu.setState(MaterialMenuDrawable.IconState.BURGER);
}
}
});
}
I hope it helps.
I am using Xamarin Android, and for AppCompatActivity I also used this method which did not work for me.
SupportActionBar.SetHomeButtonEnabled(true);
but after finding on internet and I found another method, which worked for me, and showed the home navigation button.
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
My question is very clear that i want to change the Up icon When NavigationDrawer open and closed. So please tell me how to Change the upp icon in anction bar. I have tried so much but i m not able to do. ii have used custom layout to set the title. Thanks in advance
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
actionBar.setCustomView(R.layout.center_action_bar_text);
actionBar.setTitle("dvds");
View view = actionBar.getCustomView();
TextView textView = (TextView) view.findViewById(R.id.title);
textView.setText("zfdgfdg");
actionBar.setDisplayShowHomeEnabled(true);
actionBar.setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);
---------------------------------
drawerListView.setAdapter(drawerListAdapter);
DrawerLayout drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
drawerToggle = new ActionBarDrawerToggle(HomeActivity.this,
drawerLayout, R.drawable.abc_ic_clear_search_api_holo_light, R.string.drawer_open,
R.string.drawer_close){
#Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
}
#Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
}
};
drawerLayout.setDrawerListener(drawerToggle);
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
drawerToggle.syncState();
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (drawerToggle.onOptionsItemSelected(item)) {
return true;
}
return super.onOptionsItemSelected(item);
}
Add this method to your code:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
drawerToggle.onConfigurationChanged(newConfig);
}
i have other one answer
just add this method:-
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
// if nav drawer is opened, hide the action items
boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
//boolean drawerOpen1 = mDrawerLayout.isDrawerOpen(this.slider);
//menu.findItem(R.id.sliding).setVisible(!drawerOpen);
if(drawerOpen)
{
menu.findItem(R.id.sliding).setIcon(android.R.drawable.ic_menu_close_clear_cancel);
}
else {
menu.findItem(R.id.sliding).setIcon(R.drawable.menuicon);
}
//menu.findItem(R.id.sliding).setIcon(R.drawable.ic_launcher);
//menu.findItem(R.id.action_settings).setVisible(!drawerOpen1);
return super.onPrepareOptionsMenu(menu);
}
for that method call you need to use this tow method
invalidateOptionsMenu();
// calling onPrepareOptionsMenu() to hide action bar icons
when menu is open
public void onDrawerOpened(View drawerView) {
getActionBar().setTitle(mDrawerTitle);
//mDrawerLayout.openDrawer(Gravity.END);
// calling onPrepareOptionsMenu() to hide action bar icons
invalidateOptionsMenu();
}
when menu is close
public void onDrawerClosed(View view) {
getActionBar().setTitle(mTitle);
//menu.findItem(R.id.sliding).;
//mDrawerLayout.closeDrawer(Gravity.END);
// calling onPrepareOptionsMenu() to show action bar icons
invalidateOptionsMenu();
}
I have two fragments in an activity. When fragment A is showing, I want the navigation drawer burger icon to show and the navigation drawer to work. When fragment B is showing, I want the back arrow to show and when it's clicked do an up navigation. However, I can't seem to get the new AppCompat v7 toolbar to show the up arrow at all inside my ActionBarActivity unless the nav drawer is open.
In my activity, for my onCreate() method I have...
toolbar = (Toolbar) findViewById(R.id.toolbar);
if (toolbar != null) {
setSupportActionBar(toolbar);
}
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, toolbar, R.string.drawer_open, R.string.drawer_close);
mDrawerLayout.setDrawerListener(mDrawerToggle);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
And then I call mDrawerToggle.syncState(); in my onPostCreate()
I've tried searching on how to programatically trigger the toolbar icon to the back arrow but nothing has worked. From what I've gathered, calling
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
from my fragment should change the icon but that's not the case. This may be a stupid question, but what am I doing wrong?
From what I have seen in the source code of v7 ActionBarDrawerToggle, you can animate the icon to different states without having the drawer being opened.
private enum ActionDrawableState{
BURGER, ARROW
}
private static void toggleActionBarIcon(ActionDrawableState state, final ActionBarDrawerToggle toggle, boolean animate){
if(animate) {
float start = state == ActionDrawableState.BURGER ? 0f : 1.0f;
float end = Math.abs(start - 1);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
ValueAnimator offsetAnimator = ValueAnimator.ofFloat(start, end);
offsetAnimator.setDuration(300);
offsetAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
offsetAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
float offset = (Float) animation.getAnimatedValue();
toggle.onDrawerSlide(null, offset);
}
});
offsetAnimator.start();
}else{
//do the same with nine-old-androids lib :)
}
}else{
if(state == ActionDrawableState.BURGER){
toggle.onDrawerClosed(null);
}else{
toggle.onDrawerOpened(null);
}
}
}
Morphing between Burger and Arrow depends on values between 0f and 1.0f, basically these are values that the drawer passes to the ActionBarDrawerToggle.
I used ValueAnimator to animate values in this range, i.e mimicking the drawer toggling.
null arguments are safe because ActionBarDrawerToggle does not care at all about drawer views.
Make sure you take a look at new interpolators to do the animation fully-by-the-book of material design guidelines:
fast_out_linear_in
fast_out_slow_in
Another approach is to access mSlider private field of the ActionBarDrawer through reflection and call setPosition(float position) method to toggle between Burger and Arrow.
mSlider is of type (extends) DrawerArrowDrawable.
Personally, I always try to avoid reflection, as long as there is no other way to do your dirty work.
As Support Library updated to 23.0.0, there is a better way to play drawer-arrow animation. So I'm going to improve #Nikola's answer. Here's code:
public static void playDrawerToggleAnim(final DrawerArrowDrawable d) {
float start = d.getProgress();
float end = Math.abs(start - 1);
ValueAnimator offsetAnimator = ValueAnimator.ofFloat(start, end);
offsetAnimator.setDuration(300);
offsetAnimator.setInterpolator(new AccelerateDecelerateInterpolator());
offsetAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
float offset = (Float) animation.getAnimatedValue();
d.setProgress(offset);
}
});
offsetAnimator.start();
}
And call it whenever you want by:
playDrawerToggleAnim((DrawerArrowDrawable) toolbar.getNavigationIcon());
getSupportFragmentManager().addOnBackStackChangedListener(new FragmentManager.OnBackStackChangedListener() {
#Override
public void onBackStackChanged() {
int stackHeight = getSupportFragmentManager().getBackStackEntryCount();
if (stackHeight > 0) { // if we have something on the stack (doesn't include the current shown fragment)
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
} else {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
getSupportActionBar().setHomeButtonEnabled(false);
}
}
});
After ...
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
getSupportFragmentManager().popBackStack();
return true;
....
}
In my case the icon is animating:
I have used ActionBarDrawerToggle v7.
MainActivity:
Toolbar toolbar = (Toolbar) findViewById(R.id.tool1);
setSupportActionBar(toolbar);
toolbar.setTitle("ToolBar Demo");
toolbar.setLogo(R.drawable.ic_launcher);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawerLayout);
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, toolbar,
R.string.open_navigation_drawer,
R.string.close_navigation_drawer) {
#Override
public void onDrawerSlide(View drawerView, float slideOffset) {
// TODO Auto-generated method stub
super.onDrawerSlide(drawerView, slideOffset);
}
/** Called when a drawer has settled in a completely closed state. */
#Override
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
getSupportActionBar().setTitle("hello");
}
/** Called when a drawer has settled in a completely open state. */
#Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
getSupportActionBar().setTitle("hi");
}
};
mDrawerLayout.setDrawerListener(mDrawerToggle);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) { // <---- added
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onPostCreate(Bundle savedInstanceState) { // <---- added
super.onPostCreate(savedInstanceState);
mDrawerToggle.syncState(); // important statetment for drawer to
// identify
// its state
}
#Override
public void onConfigurationChanged(Configuration newConfig) { // <---- added
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
}
#Override
public void onBackPressed() {
if (mDrawerLayout.isDrawerOpen(Gravity.START | Gravity.LEFT)) { // <----
// added
mDrawerLayout.closeDrawers();
return;
}
super.onBackPressed();
}
I've implemented the newest appcompat library and using the Toolbar as action bar. But the problem is I cannot catch the home button / hamburger icon click event. I've tried and looked everything but doesn't seem to find a similar problem.
This is my Activity class :
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// Set up the drawer.
navDrawerFragment =
(NavigationDrawerFragment) getSupportFragmentManager()
.findFragmentById(R.id.navigation_drawer);
navDrawerFragment.setUp(
R.id.navigation_drawer,
(DrawerLayout) findViewById(R.id.drawer_layout),
toolbar);
}
And this is my NavigationDrawerFragment class :
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
currentSelectedPosition = savedInstanceState.getInt(
STATE_SELECTED_POSITION);
fromSavedInstanceState = true;
}
// Select either the default item (0) or the last selected item.
selectItem(currentSelectedPosition);
}
#Override
public void onActivityCreated (Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Indicate that this fragment would like
// to influence the set of actions in the action bar.
setHasOptionsMenu(true);
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
drawerListView = (ListView) inflater.inflate(
R.layout.fragment_navigation_drawer, container, false);
drawerListView.setOnItemClickListener(
new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent,
View view, int position, long id) {
selectItem(position);
}
});
//mDrawerListView.setAdapter();
//mDrawerListView.setItemChecked(mCurrentSelectedPosition, true);
return drawerListView;
}
public void setUp(int fragmentId, DrawerLayout drawerLayout, Toolbar toolbar) {
fragmentContainerView = getActivity().findViewById(fragmentId);
this.drawerLayout = drawerLayout;
// set a custom shadow that overlays the main
// content when the drawer opens
drawerLayout.setDrawerShadow(
R.drawable.drawer_shadow, GravityCompat.START);
// set up the drawer's list view
// with items and click listener
ActionBar actionBar = getActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeButtonEnabled(true);
// ActionBarDrawerToggle ties together the the proper interactions
// between the navigation drawer and the action bar app icon.
drawerToggle = new ActionBarDrawerToggle(
getActivity(),
drawerLayout,
toolbar,
R.string.navigation_drawer_open,
R.string.navigation_drawer_close) {
public void onDrawerClosed(View view) {
super.onDrawerClosed(view);
}
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
}
};
// If the user hasn't 'learned' about the drawer,
// open it to introduce them to the drawer,
// per the navigation drawer design guidelines.
if (!userLearnedDrawer && !fromSavedInstanceState) {
drawerLayout.openDrawer(fragmentContainerView);
}
// Defer code dependent on restoration of previous instance state.
drawerLayout.post(new Runnable() {
#Override
public void run() {
drawerToggle.syncState();
}
});
drawerLayout.setDrawerListener(drawerToggle);
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putInt(STATE_SELECTED_POSITION, currentSelectedPosition);
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Forward the new configuration the drawer toggle component.
drawerToggle.onConfigurationChanged(newConfig);
}
#Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
Log.d("cek", "item selected");
if (drawerToggle.onOptionsItemSelected(item)) {
Log.d("cek", "home selected");
return true;
}
return super.onOptionsItemSelected(item);
}
when I clicked a menu item, the log "item selected" gets called. But when I click on the home button, it opens navigation drawer but the log "home selected" never get called. I've set onOptionsItemSelected method inside my Activity as well, but it still doesn't get called.
If you want to know when home is clicked is an AppCompatActivity then you should try it like this:
First tell Android you want to use your Toolbar as your ActionBar:
setSupportActionBar(toolbar);
Then set Home to be displayed via setDisplayShowHomeEnabled like this:
getSupportActionBar().setDisplayShowHomeEnabled(true);
Finally listen for click events on android.R.id.home like usual:
#Override
public boolean onOptionsItemSelected(MenuItem menuItem) {
if (menuItem.getItemId() == android.R.id.home) {
Timber.d("Home pressed");
}
return super.onOptionsItemSelected(menuItem);
}
If you want to know when the navigation button is clicked on a Toolbar in a class other than AppCompatActivity you can use these methods to set a navigation icon and listen for click events on it. The navigation icon will appear on the left side of your Toolbar where the the "home" button used to be.
toolbar.setNavigationIcon(getResources().getDrawable(R.drawable.ic_nav_back));
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("cek", "home selected");
}
});
If you want to know when the hamburger is clicked and when the drawer opens, you're already listening for these events via onDrawerOpened and onDrawerClosed so you'll want to see if those callbacks fit your requirements.
mActionBarDrawerToggle = mNavigationDrawerFragment.getActionBarDrawerToggle();
mActionBarDrawerToggle.setToolbarNavigationClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// event when click home button
}
});
in mycase this code work perfect
This is how I do it to return to the right fragment otherwise if you have several fragments on the same level it would return to the first one if you don´t override the toolbar back button behavior.
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
finish();
}
});
I think the correct solution with support library 21 is the following
// action_bar is def resource of appcompat;
// if you have not provided your own toolbar I mean
Toolbar toolbar = (Toolbar) findViewById(R.id.action_bar);
if (toolbar != null) {
// change home icon if you wish
toolbar.setLogo(this.getResValues().homeIconDrawable());
toolbar.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
//catch here title and home icon click
}
});
}
I have handled back and Home button in Navigation Drawer like
public class HomeActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
private ActionBarDrawerToggle drawerToggle;
private DrawerLayout drawerLayout;
NavigationView navigationView;
private Context context;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
resetActionBar();
navigationView = (NavigationView) findViewById(R.id.navigation_view);
navigationView.setNavigationItemSelectedListener(this);
//showing first fragment on Start
getSupportFragmentManager().beginTransaction().setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN).replace(R.id.content_fragment, new FirstFragment()).commit();
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
//listener for home
if(id==android.R.id.home)
{
if (getSupportFragmentManager().getBackStackEntryCount() > 0)
onBackPressed();
else
drawerLayout.openDrawer(navigationView);
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onBackPressed() {
if (drawerLayout.isDrawerOpen(GravityCompat.START))
drawerLayout.closeDrawer(GravityCompat.START);
else
super.onBackPressed();
}
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Begin the transaction
Fragment fragment = null;
// Handle navigation view item clicks here.
int id = item.getItemId();
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (id == R.id.nav_companies_list) {
fragment = new FirstFragment();
// Handle the action
}
// Begin the transaction
if(fragment!=null){
if(item.isChecked()){
if(getSupportFragmentManager().getBackStackEntryCount()==0){
drawer.closeDrawers();
}else{
removeAllFragments();
getSupportFragmentManager().beginTransaction().setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE).replace(R.id.WikiCompany, fragment).commit();
drawer.closeDrawer(GravityCompat.START);
}
}else{
removeAllFragments();
getSupportFragmentManager().beginTransaction().setTransition(FragmentTransaction.TRANSIT_FRAGMENT_CLOSE).replace(R.id.WikiCompany, fragment).commit();
drawer.closeDrawer(GravityCompat.START);
}
}
return true;
}
public void removeAllFragments(){
getSupportFragmentManager().popBackStackImmediate(null,
FragmentManager.POP_BACK_STACK_INCLUSIVE);
}
public void replaceFragment(final Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.replace(R.id.WikiCompany, fragment).addToBackStack("")
.commit();
}
public void updateDrawerIcon() {
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
try {
Log.i("", "BackStackCount: " + getSupportFragmentManager().getBackStackEntryCount());
if (getSupportFragmentManager().getBackStackEntryCount() > 0)
drawerToggle.setDrawerIndicatorEnabled(false);
else
drawerToggle.setDrawerIndicatorEnabled(true);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}, 50);
}
public void resetActionBar()
{
//display home
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
}
public void setActionBarTitle(String title) {
getSupportActionBar().setTitle(title);
}
}
and In each onViewCreated I call
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
((HomeActivity)getActivity()).updateDrawerIcon();
((HomeActivity) getActivity()).setActionBarTitle("List");
}
This is how I implemented it pre-material design and it seems to still work now I've switched to the new Toolbar. In my case I want to log the user in if they attempt to open the side nav while logged out, (and catch the event so the side nav won't open). In your case you could not return true;.
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (!isLoggedIn() && item.getItemId() == android.R.id.home) {
login();
return true;
}
return mDrawerToggle.onOptionsItemSelected(item) || super.onOptionsItemSelected(item);
}
I changed the DrawerLayout a bit to get the events and be able to consume and event, such as if you want to use the actionToggle as back if you are in detail view:
public class ListenableDrawerLayout extends DrawerLayout {
private OnToggleButtonClickedListener mOnToggleButtonClickedListener;
private boolean mManualCall;
public ListenableDrawerLayout(Context context) {
super(context);
}
public ListenableDrawerLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ListenableDrawerLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* Sets the listener for the toggle button
*
* #param mOnToggleButtonClickedListener
*/
public void setOnToggleButtonClickedListener(OnToggleButtonClickedListener mOnToggleButtonClickedListener) {
this.mOnToggleButtonClickedListener = mOnToggleButtonClickedListener;
}
/**
* Opens the navigation drawer manually from code<br>
* <b>NOTE: </b>Use this function instead of the normal openDrawer method
*
* #param drawerView
*/
public void openDrawerManual(View drawerView) {
mManualCall = true;
openDrawer(drawerView);
}
/**
* Closes the navigation drawer manually from code<br>
* <b>NOTE: </b>Use this function instead of the normal closeDrawer method
*
* #param drawerView
*/
public void closeDrawerManual(View drawerView) {
mManualCall = true;
closeDrawer(drawerView);
}
#Override
public void openDrawer(View drawerView) {
// Check for listener and for not manual open
if (!mManualCall && mOnToggleButtonClickedListener != null) {
// Notify the listener and behave on its reaction
if (mOnToggleButtonClickedListener.toggleOpenDrawer()) {
return;
}
}
// Manual call done
mManualCall = false;
// Let the drawer layout to its stuff
super.openDrawer(drawerView);
}
#Override
public void closeDrawer(View drawerView) {
// Check for listener and for not manual close
if (!mManualCall && mOnToggleButtonClickedListener != null) {
// Notify the listener and behave on its reaction
if (mOnToggleButtonClickedListener.toggleCloseDrawer()) {
return;
}
}
// Manual call done
mManualCall = false;
// Let the drawer layout to its stuff
super.closeDrawer(drawerView);
}
/**
* Interface for toggle button callbacks
*/
public static interface OnToggleButtonClickedListener {
/**
* The ActionBarDrawerToggle has been pressed in order to open the drawer
*
* #return true if we want to consume the event, false if we want the normal behaviour
*/
public boolean toggleOpenDrawer();
/**
* The ActionBarDrawerToggle has been pressed in order to close the drawer
*
* #return true if we want to consume the event, false if we want the normal behaviour
*/
public boolean toggleCloseDrawer();
}
}
The easiest approach we could do is change the home icon to a known icon and compare drawables (because android.R.id.home icon can differ to different api versions
so set a toolbar as actionbar
SetSupportActionBar(_toolbar);
_toolbar.NavigationIcon = your_known_drawable_here;
for (int i = 0; i < _toolbar.ChildCount; i++)
{
View v = _toolbar.GetChildAt(i);
if (v is ImageButton)
{
ImageButton imageButton = v as ImageButton;
if (imageButton.Drawable.GetConstantState().Equals(_bookMarkIcon.GetConstantState()))
{
//here v is the widget that contains the home icon you can add your click events here
}
}
}
In my case I had to put the icon using:
toolbar.setNavigationIcon(R.drawable.ic_my_home);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
And then listen to click events with default onOptionsItemSelected and android.R.id.home id
For anyone looking for a Xamarin implementation (since events are done differently in C#), I simply created this NavClickHandler class as follows:
public class NavClickHandler : Java.Lang.Object, View.IOnClickListener
{
private Activity mActivity;
public NavClickHandler(Activity activity)
{
this.mActivity = activity;
}
public void OnClick(View v)
{
DrawerLayout drawer = (DrawerLayout)mActivity.FindViewById(Resource.Id.drawer_layout);
if (drawer.IsDrawerOpen(GravityCompat.Start))
{
drawer.CloseDrawer(GravityCompat.Start);
}
else
{
drawer.OpenDrawer(GravityCompat.Start);
}
}
}
Then, assigned a custom hamburger menu button like this:
SupportActionBar.SetDisplayHomeAsUpEnabled(true);
SupportActionBar.SetDefaultDisplayHomeAsUpEnabled(false);
this.drawerToggle.DrawerIndicatorEnabled = false;
this.drawerToggle.SetHomeAsUpIndicator(Resource.Drawable.MenuButton);
And finally, assigned the drawer menu toggler a ToolbarNavigationClickListener of the class type I created earlier:
this.drawerToggle.ToolbarNavigationClickListener = new NavClickHandler(this);
And then you've got a custom menu button, with click events handled.
Try this code
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if(id == android.R.id.home){
//You can get
}
return super.onOptionsItemSelected(item);
}
Add below code to your onCreate() metod
ActionBar ab = getSupportActionBar();
ab.setDisplayHomeAsUpEnabled(true);
Apart from the answer provided by MrEngineer13, there is also another possible reason why the click event might not have been captured in the onOptionsSelected method. Your DrawerLayout may have overlayed your Toolbar's interface component in the layout XML file. Therefore, whenever you attempt to click the Home button, you're only clicking the DrawerLayout, but not the Home button that's located beneath it.
All you have to do now is rearrange your Toolbar in the corresponding layout XML file so that it is not blocked by any other UI component.
Programmatically, I did attempt to call the bringToFront() method on the toolbar (toolbar.bringToFront()). However, in my app's context, it does not seem to be the solution.
I have a problem with the NavigationDrawer icon, I want it to be visible within the ActionBar. It is needed to show the user, that he can open the drawer in my app by swiping from the left edge of the screen.
I use this code before without any problems, but in this application it isn't working well, I don't know what the problem can be. Please help me.
Here is my code:
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerList = (ListView) findViewById(R.id.left_drawer);
ArrayList<Integer> smIcon_adrs = new ArrayList<Integer>();
smIcon_adrs.add(R.drawable.sm_font);
smIcon_adrs.add(R.drawable.sm_size);
smIcon_adrs.add(R.drawable.sm_count);
smIcon_adrs.add(R.drawable.sm_about);
ArrayAdapter<Integer> sm_adapter = new smIcoAdapter(getBaseContext(),
smIcon_adrs);
mDrawerList.setAdapter(sm_adapter);
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
R.drawable.ic_drawer, R.string.hello_world, R.string.app_name) {
/** Called when a drawer has settled in a completely closed state. */
public void onDrawerClosed(View view) {
getSupportActionBar().setTitle("دعا عهد");
supportInvalidateOptionsMenu();
super.onDrawerClosed(view);
}
/** Called when a drawer has settled in a completely open state. */
public void onDrawerOpened(View drawerView) {
getSupportActionBar().setTitle("امکانات");
supportInvalidateOptionsMenu();
super.onDrawerOpened(drawerView);
// onPrepareOptionsMenu()
}
};
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
mDrawerLayout.setDrawerListener(mDrawerToggle);
and here:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu items for use in the action bar
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.main, menu);
return super.onCreateOptionsMenu(menu);
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
mDrawerToggle.syncState();
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_play:
if (mp.isPlaying()) {
item.setIcon(R.drawable.actn_play);
mp.pause();
} else {
updateProgressBar();
mp.start();
item.setIcon(R.drawable.actn_stop);
}
break;
}
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
return super.onOptionsItemSelected(item);
}
public boolean onPrepareOptionsMenu(Menu menu) {
mDrawerLayout.isDrawerOpen(mDrawerList);
// menu.findItem(R.id.action_settings).setVisible(!drawerOpen);
return super.onPrepareOptionsMenu(menu);
}
Here is someone with a similar problem, you might test the solution posted there: https://stackoverflow.com/a/23332975/1738838.
According to that you are missing this method:
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
}