I'm trying to make a simple navigation drawer, matching the material guidelines. I'm following along the official training. Everything is running well, only a tap on the hamburger icon won't open the drawer. I can open the drawer with a swipe from the side, only the hamburger isn't working. I already looked up some other questions like this one, but nothing helped. What did I miss?
Here is my code:
Activity.java:
public class stream extends ActionBarActivity {
private DrawerLayout mDrawerLayout;
private ActionBarDrawerToggle mDrawerToggle;
private String[] mDrawerTitles;
private ListView mDrawerList;
private Toolbar mToolbar;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_stream);
// Init the Support-toolbar
mToolbar = (Toolbar) findViewById(R.id.toolbar);
if (mToolbar != null) {
setSupportActionBar(mToolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, mToolbar,
R.string.navigation_drawer_open, R.string.navigation_drawer_close);
mDrawerLayout.setDrawerListener(mDrawerToggle);
// enable ActionBar app icon to behave as action to toggle nav drawer
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = new MenuInflater(this);
inflater.inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
mDrawerToggle.syncState();
}
#Override
public void onBackPressed() {
if(mDrawerLayout.isDrawerOpen(Gravity.START|Gravity.LEFT)){
mDrawerLayout.closeDrawers();
return;
}
super.onBackPressed();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Pass any configuration change to the drawer toggle
mDrawerToggle.onConfigurationChanged(newConfig);
}
}
Layout.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="de.square7.gtz.lwenzahn.stream"
android:background="#color/ColorBackground">
<!-- Toolbar -->
<include layout="#layout/toolbar"/>
<android.support.v4.widget.DrawerLayout
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Content View -->
<FrameLayout
android:id="#+id/content_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="56dp"/>
<!-- Drawer -->
<ListView
android:id="#+id/left_drawer"
android:layout_width="270dp"
android:layout_height="match_parent"
android:focusableInTouchMode="false"
android:choiceMode="singleChoice"
android:background="#ffffffff"
android:layout_gravity="start"
android:elevation="8dp" >
</ListView>
</android.support.v4.widget.DrawerLayout>
You are not using the DrawerLayout as the root layout of the activity. You are almost there but you see how you use the RelativeLayout as the root (or at least that is what I infer from the posted xml - the RelativeLayout does not look like it has a closing tag so maybe you just missed it)?
The NavigationDrawer opens on the tap of the "hamburger" (or icon) only when it is the root so that Android knows that the DrawerLayout is encompassing everything. My guess is the toolbar you are including is interfering with the layout.
Related
I have two navigation views in my Activity. One enters from the right and the other enters from the left.
In the navigtionview that enters from from the left, different fragments are started when when the items are clicked. And also, this same navigationview has menu items which is common to all the launched fragments. I don't have any problem with this one.
Now, the navigationview that enters from the right has menu items which are only peculiar to the particular fragment started when the first item in the left entering navigationview is clicked. What this means is that, when you clicked the first item in the left entering navigation drawer, a fragament is started, and items in the right entering navigationview has items related to this fragment.
So, this right navigationview is stared when a menuitem in the toolbar is clicked. And this menu item is not visible when other fragments (apart from the aforementioned) is in view.
The problem I have is that, even when the right entering navigationview cannot be launched through the menuitem in other fragments, it can still be started by sliding the right edge of the screen. So I want to totally disable the sliding feature of this right entering navigationview, so it can only be launched when the menu item is clicked.
Codes
activity_main
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
android:id="#+id/drawer_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="#layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="false"
app:headerLayout="#layout/nav_header_main"
app:menu="#menu/activity_main_drawer"/>
<android.support.design.widget.NavigationView
android:id="#+id/cat_nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"
android:fitsSystemWindows="false">
/** This navigationview enters from the right, I start a fragment with framelayout below.
The fragment contains a recyclerview **/
<FrameLayout
android:id="#+id/transport_cat_container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>
Snippets of MainActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
ActionBarDrawerToggle mDrawerToggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close) {
#Override
public void onDrawerClosed(View v){
super.onDrawerClosed(v);
}
#Override
public void onDrawerOpened(View v) {
super.onDrawerOpened(v);
}
};
drawer.addDrawerListener(mDrawerToggle);
mDrawerToggle.syncState();
navigationView.setNavigationItemSelectedListener(this);
}
#Override
public void onBackPressed() {
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else if (drawer.isDrawerOpen(GravityCompat.END)) {
drawer.closeDrawer(GravityCompat.END);
} else {
super.onBackPressed();
}
}
ActionBarDrawerToggle mDrawerToggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close) {
#Override
public void onDrawerClosed(View v){
super.onDrawerClosed(v);
}
#Override
public void onDrawerOpened(View v) {
super.onDrawerOpened(v);
}
};
drawer.addDrawerListener(mDrawerToggle);
mDrawerToggle.syncState();
navigationView.setNavigationItemSelectedListener(this);
Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
Fragment fragment;
if (id == R.id.menu_cars) {
fragment = new CarsFragment();
startCarsFrag() //Method to start CarsFragment()
//The right entering drawer should only be enabled for this fragment
}
if (id == R.id.menu_trains) {
fragment = new TrainsFragment();
startTrainFrag() //Method to start TrainsFragment
}
if (id == R.id.menu_lorries) {
fragment = new LorriesFragment();
startLorriesFrag() //Method to start LorriesFragment
}
if (drawer != null) {
drawer.closeDrawer(GravityCompat.START);
}
return true;
}
The DrawerLayout#setDrawerLockMode() method is what you're looking for. When locked, a drawer View cannot be dragged open/closed, though it will still respond to the openDrawer() and closeDrawer*() methods.
Since you're using two drawers, and want to lock only the one, you'll need to call the method with a second argument to indicate which drawer to lock/unlock. For example, to lock your secondary drawer closed:
drawer.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED, GravityCompat.END);
As the page on Android Developers says
The user can bring the navigation drawer onto the screen by swiping from the left edge of the screen or by touching the application icon on the action bar.
But strangely the navigation drawer on my activity does not respond to sliding action. It toggles only on touching the icon on the action bar. Below is my implementation of the navigation drawer
mNavigationDrawerFragment = (NavigationDrawerFragment)
getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
// Set up the drawer.
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mNavigationDrawerFragment.setUp(
R.id.navigation_drawer,
drawerLayout);
Is there any possible explanation for this? What I doubt is my activity by default has the layout of one of its fragments. So is that the reason?
Edit: The layout file of my activity
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainPage">
<!-- The main ocntent view -->
<FrameLayout android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
<!-- The navigation drawer-->
<fragment android:id="#+id/navigation_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:divider="#android:color/transparent"
android:name="com.example.android.handsfree.NavigationDrawerFragment"
tools:layout="#layout/fragment_navigation_drawer" />
Your ´NavigationDrawerFragment´ already creates a drawer Toggle for you inside its `setUp´ method.
You should not create a new one inside your ´MainPage´ Activity.
Notes:
You can use the android.support.v7.app.ActionBarDrawerToggle instead of the v4 one inside the NavigationDrawerFragment.
Update:
The problem seems solved now. There were 2 Issues:
The OP created a second drawer toggle in it's MainPage - Activity but there was already one created inside the NavigationDrawerFragment's setUp method, which gets called by the MainPage in order to set up the drawer. (This is basicly outsourc[ecoding]ing some of the drawer stuff to the drawer fragment.)
The OP locked the drawer inside onCreateOptionsMenu by calling a method which sets the DrawerLockMode to LOCK_MODE_LOCKED_CLOSED. He never reverted this change.
You should use:
drawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_UNLOCKED);
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white" >
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ListView
android:id="#+id/listview_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#color/drawer"
android:choiceMode="singleChoice" />
on your activity
drawlayout = (DrawerLayout) findViewById(R.id.drawer_layout);
listData = (ListView) findViewById(R.id.listview_drawer);
drawlayout.setDrawerShadow(R.drawable.drawer_shadow,
GravityCompat.START);
Add these fields in your activity class:
private ActionBarDrawerToggle mDrawerToggle;
private DrawerLayout mDrawerLayout;
Then, inside your activity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
...
// enabling action bar app icon and behaving it as toggle button
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true)
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
R.drawable.ic_drawer, //nav menu toggle icon
R.string.app_name, // nav drawer open - description for accessibility
R.string.app_name // nav drawer close - description for accessibility
){
public void onDrawerClosed(View view) {
// calling onPrepareOptionsMenu() to show action bar icons
invalidateOptionsMenu();
}
public void onDrawerOpened(View drawerView) {
// calling onPrepareOptionsMenu() to hide action bar icons
invalidateOptionsMenu();
}
};
mDrawerLayout.setDrawerListener(mDrawerToggle);
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// toggle nav drawer on selecting action bar app icon/title
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
return super.onOptionsItemSelected(item);
}
/**
* When using the ActionBarDrawerToggle, you must call it during
* onPostCreate() and onConfigurationChanged()...
*/
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Sync the toggle state after onRestoreInstanceState has occurred.
mDrawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
// Pass any configuration change to the drawer toggls
mDrawerToggle.onConfigurationChanged(newConfig);
}
ic_drawer is a .png image which located in drawable resources. You can search this image on Google.
API level to be used is 11+.
Hope it helps for you.
1- replace the tag by :
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainPage">
<!-- The main ocntent view -->
<FrameLayout android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
<!-- The navigation drawer-->
<ListView android:id="#+id/navigation_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:divider="#android:color/transparent" />
</android.support.v4.widget.DrawerLayout>
2- use this code in the onCreate function u can use the v4 ActionBarDrawerToggle or the v7 her i use the v4:
private DrawerLayout mDrawerLayout;
private ActionBarDrawerToggle mDrawerToggle;
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,R.drawable.ic_drawer,
R.string.app_name,R.string.app_name) {
public void onDrawerClosed(View view) {
getActionBar().setTitle(mTitle);
invalidateOptionsMenu();
}
public void onDrawerOpened(View drawerView) {
getActionBar().setTitle(mDrawerTitle);
invalidateOptionsMenu();
}
};
mDrawerLayout.setDrawerListener(mDrawerToggle);
First of all I know this question appeared here before but after trying a lot I still didn't succeed.
I working on the example from
Android Developers site.
I'm trying to set the menu to be opened from right to left instead of how its implementing in the example (from left to right). In addition I want to move the open menu button to the right side of the action bar. I also red some answers here, for example in this answer.
I try to change the gravity of the views and the layouts but I get the error:
no drawer view found with absolute gravity LEFT
Can you please help me to figure out what is the problem in my code and what should I change in order to set the menu to be opened from the right, and to move the action bar button to the right side?
the xml code is here:
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout"
android:layout_gravity="right"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<FrameLayout
android:id="#+id/content_frame"
android:layoutDirection="rtl"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<ListView android:id="#+id/left_drawer"
android:layout_width="200dp"
android:layout_height="match_parent"
android:layout_gravity="right"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="10dp"
android:background="#111"/>
</android.support.v4.widget.DrawerLayout>
In your main layout set your ListView gravity to right:
android:layout_gravity="right"
Also in your code :
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
R.drawable.ic_drawer, R.string.drawer_open,
R.string.drawer_close) {
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item != null && item.getItemId() == android.R.id.home) {
if (mDrawerLayout.isDrawerOpen(Gravity.RIGHT)) {
mDrawerLayout.closeDrawer(Gravity.RIGHT);
}
else {
mDrawerLayout.openDrawer(Gravity.RIGHT);
}
}
return false;
}
};
hope it works :)
Add this code to manifest:
<application android:supportsRtl="true">
and then write this code on Oncreate:
getWindow().getDecorView().setLayoutDirection(View.LAYOUT_DIRECTION_RTL);
It works for me. ;)
SOLUTION
your_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="end">
<include layout="#layout/app_bar_root"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"
android:fitsSystemWindows="true"
app:itemTextColor="#color/black"
app:menu="#menu/activity_root_drawer" />
</android.support.v4.widget.DrawerLayout>
YourActivity.java:
#Override
protected void onCreate(Bundle savedInstanceState) {
//...
toolbar = (Toolbar) findViewById(R.id.toolbar);
drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (drawer.isDrawerOpen(Gravity.RIGHT)) {
drawer.closeDrawer(Gravity.RIGHT);
} else {
drawer.openDrawer(Gravity.RIGHT);
}
}
});
//...
}
This answer is useful to set the navigation be open from right to left, but it has no solution to set its icon to be right side. This code can fix it. If you give it the drawer as its first param and ViewCompat.LAYOUT_DIRECTION_RTL as its second param, the entier layout will be set to RTL. It is a quick and simple solution, but I don't think it can be a correct solution for who that want to only set the menu to be opened from right to left and set its icon to be on right side. (Although, it's depended to your purpose.) However, I suggest giving the toolbar instead of the drawer. In this way just the toolbar has become RTL. So I think the combination of these 2 answers can exactly do what you want.
According to these descriptions, your code should be like this:
(Add these lines to onCreate method)
final DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); // Set it final to fix the error that will be mention below.
ViewCompat.setLayoutDirection(toolbar, ViewCompat.LAYOUT_DIRECTION_RTL);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (drawer.isDrawerOpen(Gravity.RIGHT))
drawer.closeDrawer(Gravity.RIGHT);
else
drawer.openDrawer(Gravity.RIGHT);
}
});
Notice that you should make drawer final, otherwise you will get this error:
Variable 'drawer' is accessed from within inner class, needs to be
declared final
And don't forget to use end instead of start in onNavigationItemSelected method:
drawer.closeDrawer(GravityCompat.END);
and in your activity_main.xml
<android.support.v4.widget.DrawerLayout
android:id="#+id/drawer_layout"
tools:openDrawer="end">
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_gravity="end"/>
</android.support.v4.widget.DrawerLayout>
Here is the documentation on the drawer and it appears that you can configure it to pull out from the left or right.
Drawer positioning and layout is controlled using the android:layout_gravity attribute on child views corresponding to which side of the view you want the drawer to emerge from: left or right. (Or start/end on platform versions that support layout direction.)
http://developer.android.com/reference/android/support/v4/widget/DrawerLayout.html
Take a look at this: slide ExpandableListView at DrawerLayout form right to left
I assume you have the ActionBarDrawerToggle implemented, the trick is to override the onOptionsItemSelected(MenuItem item) method inside the ActionBarDrawerToggle object with this:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item != null && item.getItemId() == android.R.id.home) {
if (mDrawer.isDrawerOpen(Gravity.RIGHT)) {
mDrawer.closeDrawer(Gravity.RIGHT);
} else {
mDrawer.openDrawer(Gravity.RIGHT);
}
return true;
}
return false;
}
make sure and call this from onOptionsItemSelected(MenuItem item) in the Activity:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if(mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
return super.onOptionsItemSelected(item);
}
This will allow you to use the the home button functionality. To move the button to the right side of the action bar you will have to implement a custom action item, and maybe some other stuff to get it to work like you want.
the main issue with the following error:
no drawer view found with absolute gravity LEFT
is that, you defined the
android:layout_gravity="right"
for list-view in right, but try to open the drawer from left, by calling this function:
mDrawerToggle.syncState();
and clicking on hamburger icon!
just comment the above function and try to handle open/close of menu like #Rudi said!
I have solved this problem by changing the gravity of the navigationview
android:layout_gravity
to end instead of start
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header"
app:menu="#menu/activity_drawer" />
It worked for me.
You should firstly put this code in your AppManifest.xml in the application tag:
android:supportsRtl="true"
then in your activity_main.xml file, put this piece of code:
android:layout_direction="rtl"
I did following modification to the Navigation Drawer Activity example in Android Studio. With support libraries 25.3.1.
MainActivity.java:
private DrawerLayout mDrawerLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
}
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
}
#Override
public void onBackPressed() {
if (mDrawerLayout.isDrawerOpen(GravityCompat.END)) {
mDrawerLayout.closeDrawer(GravityCompat.END);
} else {
super.onBackPressed();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
switch (itemId) {
case android.R.id.home:
finish();
return true;
case R.id.action_right_drawer:
if (mDrawerLayout.isDrawerOpen(GravityCompat.END)) {
mDrawerLayout.closeDrawer(GravityCompat.END);
} else {
mDrawerLayout.openDrawer(GravityCompat.END);
}
return true;
default:
return super.onOptionsItemSelected(item);
}
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
mDrawerLayout.closeDrawer(GravityCompat.END);
return true;
}
main.xml (download ic_menu_white_24px from https://material.io/icons/):
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item android:id="#+id/action_right_drawer"
android:title="Drawer menu"
android:icon="#drawable/ic_menu_white_24px"
android:orderInCategory="100"
app:showAsAction="always" />
</menu>
In activity_main.xml change
android:layout_gravity="start"
to
android:layout_gravity="end"
Making it open from rtl isn't good for user experience, to make it responsive to the user locale I just added the following line to my DrawerLayout parameters:
android:layoutDirection="locale"
Added it to my AppBarLayout to make the hamburger layout match the drawer opening direction too.
DrawerLayout Properties
android:layout_gravity="right|end" and tools:openDrawer="end"
NavigationView Property
android:layout_gravity="end"
XML Layout
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:layout_gravity="right|end"
tools:openDrawer="end">
<include layout="#layout/content_main" />
<com.google.android.material.navigation.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_main"
app:menu="#menu/activity_main_drawer" />
</androidx.drawerlayout.widget.DrawerLayout>
Java Code
// Appropriate Click Event or Menu Item Click Event
if (drawerLayout.isDrawerOpen(GravityCompat.END))
{
drawerLayout.closeDrawer(GravityCompat.END);
}
else
{
drawerLayout.openDrawer(GravityCompat.END);
}
//With Toolbar
toolbar = (Toolbar) findViewById(R.id.toolbar);
drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Gravity.END or Gravity.RIGHT
if (drawer.isDrawerOpen(Gravity.END)) {
drawer.closeDrawer(Gravity.END);
} else {
drawer.openDrawer(Gravity.END);
}
}
});
//...
}
In your layout file inside NavigationView set this attribute android:layout_gravity="end" and set tools:openDrawer="end" in the DrawerLayout
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".tasks.TasksActivity"
android:id="#+id/drawer_layout"
tools:openDrawer="end">
<!-- Navigation Drawer -->
<com.google.android.material.navigation.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header"
app:menu="#menu/drawer_actions" />
</androidx.drawerlayout.widget.DrawerLayout>
Output
I know this is an old question, but I've been struggling with this problem for a few days now and finally achived the solution.
If you want to use the default new project "Navigation Drawer Activity" to work with a drawer from right to left:
Create a custom DrawerLayout class:
public class CustomDrawerLayout extends DrawerLayout {
public CustomDrawerLayout(#NonNull Context context) {
super(context);
}
public CustomDrawerLayout(#NonNull Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
}
public CustomDrawerLayout(#NonNull Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
public void open() {
openDrawer(GravityCompat.END);
}
#Override
public void close() {
closeDrawer(GravityCompat.END);
}
#Override
public boolean isOpen() {
return isDrawerOpen(GravityCompat.END);
}
}
On activity_main.xml:
set DrawerLayout tools:openDrawer="end"
set NavigationView android:layout_gravity="end"
change tag view from androidx.drawerlayout.widget.DrawerLayout to your CustomDrawerLayout com.example.CustomDrawerLayout
If you create new menu options, it is important that the id of the item in menu/activity_main_drawer.xml is the same as the id of the fragment in navigation/mobile_navigation.xml.
Summarising multiple answers into one which worked for me.
Following were my requirements
1. Align navigation drawer hamburger icon to write
2. Start the navigation drawer from right to left
3. Achieve the above two points without changing the direction to rtl of the whole layout
To start the Navigation drawer from right to left
Set DrawerLayout tools:openDrawer="end"
Set NavigationView android:layout_gravity="end"
mDrawerToggle.setToolbarNavigationClickListener {
if (binding.drawerLayout.isDrawerOpen(GravityCompat.END)) {
binding.drawerLayout.closeDrawer(GravityCompat.END)
} else {
binding.drawerLayout.openDrawer(GravityCompat.END)
}
}
To set the Hamburger menu to the right
Set AppBarLayout android:layoutDirection="rtl"
I have an application, in which i want to implement a double drawer - one from the left and one from the right. Left drawer is for app navigation, right drawer is for result filtering.
So, the layout is like this:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/light_grey"
android:orientation="vertical">
<GridView
android:id="#+id/gridview"
style="#style/GridViewStyle"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:horizontalSpacing="7dp"
android:stretchMode="columnWidth"
android:verticalSpacing="7dp" />
</LinearLayout>
<ListView
android:id="#+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#111"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp" />
<ListView
android:id="#+id/right_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="end"
android:background="#111"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp" />
</android.support.v4.widget.DrawerLayout>
You can clearly see here "left_drawer" and "right_drawer", and their respective gravity - "start" and "end"
And this actually works! You can pull them both out.
The problem is, when i implement the DrawerToggle - it only opens the left drawer, and does not close the right one, so if the right drawer is opened and i press the DrawerToggle button - the left drawers opens ALSO, and overlaps the right drawer.
There are a couple of solutions i'am trying to get:
Make the same DrawerToggle button on the right side, with the same behavior and animation as the left side.
Make the drawer on the opposite side of the drawer i am trying to open - automatically close (if the left drawer is open and i press the toggle of the right drawer and vise-versa).
And i haven't figured how to do that, because DrawerToggle accepts the DrawerLayout itself as a parameter, and not the individual drawers...
I am using the Support Library.
Anyone have any ideas?
Thank you in advance.
Here is the code for a Double Drawer Activity than can be extended by other activities to implement the double drawer, assuming they have a layout like the one propposed by OP.
public class DoubleDrawerActivity extends ActionBarActivity {
private DrawerLayout mDrawerLayout;
private ActionBarDrawerToggle mDrawerToggle;
private View mLeftDrawerView;
private View mRightDrawerView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
}
#Override
protected void onStart() {
super.onStart();
if(mDrawerLayout == null || mLeftDrawerView == null || mRightDrawerView == null || mDrawerToggle == null) {
// Configure navigation drawer
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mLeftDrawerView = findViewById(R.id.left_drawer);
mRightDrawerView = findViewById(R.id.right_drawer);
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.drawable.ic_navigation_drawer, R.string.drawer_open, R.string.drawer_close) {
/** Called when a drawer has settled in a completely closed state. */
public void onDrawerClosed(View drawerView) {
if(drawerView.equals(mLeftDrawerView)) {
getSupportActionBar().setTitle(getTitle());
supportInvalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
mDrawerToggle.syncState();
}
}
/** Called when a drawer has settled in a completely open state. */
public void onDrawerOpened(View drawerView) {
if(drawerView.equals(mLeftDrawerView)) {
getSupportActionBar().setTitle(getString(R.string.app_name));
supportInvalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
mDrawerToggle.syncState();
}
}
#Override
public void onDrawerSlide(View drawerView, float slideOffset) {
// Avoid normal indicator glyph behaviour. This is to avoid glyph movement when opening the right drawer
//super.onDrawerSlide(drawerView, slideOffset);
}
};
mDrawerLayout.setDrawerListener(mDrawerToggle); // Set the drawer toggle as the DrawerListener
}
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Sync the toggle state after onRestoreInstanceState has occurred.
mDrawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
}
#Override
public boolean onPrepareOptionsMenu(Menu menu) {
// If the nav drawer is open, hide action items related to the content view
for(int i = 0; i< menu.size(); i++)
menu.getItem(i).setVisible(!mDrawerLayout.isDrawerOpen(mLeftDrawerView));
return super.onPrepareOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch(item.getItemId()) {
case android.R.id.home:
mDrawerToggle.onOptionsItemSelected(item);
if(mDrawerLayout.isDrawerOpen(mRightDrawerView))
mDrawerLayout.closeDrawer(mRightDrawerView);
return true;
}
return super.onOptionsItemSelected(item);
}
}
You can call it like this in a ToggleButton's handler for example :
mDrawerLayout.openDrawer(mDrawer);
mDrawerLayout.closeDrawer(mDrawer);
Where mDrawer is a reference to the specific drawer you need to open (be it a view or a layout), in your case, the actual ListView you wish to display.
You can use NavigationView from material design.
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="#layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_main"
app:menu="#menu/activity_main_drawer" />
<android.support.design.widget.NavigationView
android:id="#+id/nav_view2"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="end"
android:fitsSystemWindows="true"
app:headerLayout="#layout/nav_header_main"
app:menu="#menu/activity_main_drawer1" />
</android.support.v4.widget.DrawerLayout>
Here is my short solution for all who want to prevent the animation of drawer indicator if they swipe the right view. Simply implement the onDrawerSlide Method like this.
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.drawable.ic_drawer_white, 0, 0) {
#Override
public void onDrawerClosed(View view) {
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
#Override
public void onDrawerOpened(View drawerView) {
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
}
#Override
public void onDrawerSlide(View drawerView, float slideOffset) {
if (drawerView == mSlidingMenuNavigationList) {
super.onDrawerSlide(drawerView, slideOffset);
}
else {
// do nothing on all other views
}
}
};
Use the gravity constant (Gravity.LEFT or Gravity.RIGHT) of whatever drawer you want to close (as you open the other one) in onOptionsItemSelected() as shown below.
public boolean onOptionsItemSelected(MenuItem item) {
if (mDrawerToggle.onOptionsItemSelected(item)) {
// Close the right side drawer if visible
if(mDrawerLayout.isDrawerVisible(Gravity.RIGHT)) {
mDrawerLayout.closeDrawer(Gravity.RIGHT);
}
return true;
}
// Regular stuff
switch (item.getItemId()) {
case R.id.action_example:
Toast.makeText(getActivity(), "Example action.", Toast.LENGTH_SHORT).show();
return true;
}
return super.onOptionsItemSelected(item);
}
mDrawerToggle = Listener object implementing DrawerLayout.DrawerListener
See: http://developer.android.com/reference/android/support/v4/app/ActionBarDrawerToggle.html
I have solved adding this code in the onOptionsItemSelected method:
switch (item.getItemId()) {
case android.R.id.home:
if (mDrawerLayout.isDrawerOpen(mDrawerList_right)){
mDrawerLayout.closeDrawer(mDrawerList_right);
}
mDrawerLayout.openDrawer(mDrawerList_left);
}
break;
case R.id.action_drawer:
if (mDrawerLayout.isDrawerOpen(mDrawerList_left)){
mDrawerLayout.closeDrawer(mDrawerList_left);
}
mDrawerLayout.openDrawer(mDrawerList_right);
}
default:
break;
}
I have added an action button and overrided the home button of the actionbar
make a custom item and add it the right, pass to it the right drawer.
final ToggleButton ic_nav = (ToggleButton) customNav.findViewById(R.id.ic_nav);
ic_nav.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View arg0)
{
if ( mDrawerLayout.isDrawerOpen(mDrawerList) && arg0.isSelected()) {
mDrawerLayout.closeDrawer(mDrawerList);
arg0.setSelected(false);
}
else if (!mDrawerLayout.isDrawerOpen(mDrawerList) && !arg0.isSelected()){
mDrawerLayout.openDrawer(mDrawerList);
ic_nav.setSelected(false);
arg0.setSelected(true);
}
}
});
You can show two navigation views to the same drawer as:
<androidx.drawerlayout.widget.DrawerLayout
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="false">
<com.google.android.material.navigation.NavigationView
android:id="#+id/NAVIGATION_VIEW_LEFT"
android:layout_width="270dp"
android:layout_height="match_parent"
android:layout_gravity="start"/>
<com.google.android.material.navigation.NavigationView
android:id="#+id/NAVIGATION_VIEW_RIGHT"
android:layout_width="200dp"
android:layout_height="match_parent"
android:layout_gravity="right"/>
</androidx.drawerlayout.widget.DrawerLayout>
And for activity do this:
actionBarDrawerToggle = new ActionBarDrawerToggle(context, drawerLayout, R.string.nav_open, R.string.nav_close);
// pass the Open and Close toggle for the drawer layout listener
// to toggle the button
drawerLayout.addDrawerListener(actionBarDrawerToggle);
actionBarDrawerToggle.syncState();
nav_drawer_left_Iv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
drawerLayout.openDrawer(GravityCompat.START);
}
});
nav_drawer_right_Iv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
drawerLayout.openDrawer(GravityCompat.END);
}
});
I am trying to add the navigation drawer in my app.. Everything is working fine But now I still got the arrow icon although I replaced it with the ic_drawer from Android? Here's my code:
private ActionBarDrawerToggle mDrawerToggle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
DrawerLayout mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
ExpandableListView mDrawerList = (ExpandableListView) findViewById(R.id.left_drawer);
mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow,
GravityCompat.START);
mDrawerList.setAdapter(new DrawerListAdapter(this));
mDrawerList.setOnChildClickListener(new DrawerItemClickListener());
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
R.drawable.ic_launcher, R.string.drawer_open,
R.string.drawer_close);
Log.d("Mudit",
"mDrawerToggle" + mDrawerToggle.isDrawerIndicatorEnabled()); // returns true
mDrawerLayout.setDrawerListener(mDrawerToggle);
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);
getActionBar().setDisplayShowHomeEnabled(false);
}
/**
* When using the ActionBarDrawerToggle, you must call it during
* onPostCreate() and onConfigurationChanged()...
*/
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
mDrawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
return super.onOptionsItemSelected(item);
}
XML:
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<ScrollView
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
</LinearLayout>
</ScrollView>
<ExpandableListView
android:id="#+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#ffffff"
android:dividerHeight="0dp" />
</android.support.v4.widget.DrawerLayout>
I have looking at various code samples online but all of them are doing same thing. I dont know why it is not working for me.
Please help.
You'll have to use
getActionBar().setDisplayShowHomeEnabled(true);
instead of
getActionBar().setDisplayShowHomeEnabled(false);
Cheers,
Felix
EDIT: Here's how to hide the Icon via XML:
add this to your styles.xml: (Replace android:Widget.Holo.Light.ActionBar.Solid with android:Widget.Holo.ActionBar.Solid if you are using the dark action bar)
<style name="ActionBarStyle" parent="android:Widget.Holo.Light.ActionBar.Solid">
<item name="android:icon">#android:color/transparent</item>
</style>
and then add this to your Theme you have defined in AndroidManifest.xml (Standard is the AppBaseTheme in /res/values-v11/styles.xml - AppBaseTheme:
<item name="android:actionBarStyle">#style/ActionBarStyle</item>
Hope this helps!
try this code
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Sync the toggle state after onRestoreInstanceState has occurred.
actbardrawertoggle.syncState();
}
This worked for me when I wanted to get the menu icon back from the back arrow
private void updateNavigationIcon() {
if (getSupportFragmentManager().getBackStackEntryCount() == 0
&& getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(false);
toggle.syncState();
}
}
Just add the following line inside showGlobalContextActionBar() method (NavigationDrawerFragment.java class)
actionBar.setHomeAsUpIndicator(R.drawable.ic_action_menu);
Code snippet:
private void showGlobalContextActionBar() {
ActionBar actionBar = getActionBar();
actionBar.setDisplayShowTitleEnabled(true);
actionBar.setHomeAsUpIndicator(R.drawable.ic_action_menu);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
actionBar.setTitle(R.string.app_name);
}