Scrolling animation in NavigationView - android

My activity has a NavigationView inside a DrawerLayout.
When user clicks on a button in the NavigationView header, I would like to scroll to top the DrawerLayout/NavigationView with an animation.
It seems that NavigationView and DrawerLayout don't provide a method to get the actual scroll position (getScrollY() and getScrollX() always return 0) and so I can't do that.
How can I scroll to top with an animation?
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<!-- My content -->
<android.support.design.widget.NavigationView
android:id="#+id/navigation"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="#layout/navigation_view_header"
app:menu="#menu/my_navigation_items" />
</android.support.v4.widget.DrawerLayout>

you need to scroll the NavigationMenuView.
In the below code, it will scroll to top when click on any item in menu
NavigationView navigationView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
}
#Override
public boolean onNavigationItemSelected(MenuItem item) {
//here will scroll to top
((NavigationMenuView)navigationView.getChildAt(0)).smoothScrollToPosition(0);
return true;
}
EDIT: If you want to protect against possible changes down the road, you can use reflection here, like so:
// try to scroll to the top of the navigation menu, if possible
if (navigationView.getChildCount() > 0) {
View childView = navigationView.getChildAt(0);
try {
Method scroll = childView.getClass().getMethod("smoothScrollToPosition", int.class);
scroll.invoke(childView, 0);
} catch (NoSuchMethodException |
SecurityException |
IllegalAccessException |
InvocationTargetException e) {
Log.d(TAG, "smoothScrollToPosition", e);
}
}

You can simple user smoothScrollToPosition(0) as NavigationMenuView is extend from RecyclerView
see the source code for NavigationMenuView
e.g
navigationView.smoothScrollToPosition(0);

Related

How to add a back button to action bar / toolbar

I have written a piece of code as part of an app where I want to implement a back button on the action bar/tool bar such that when the button is pressed, the previous page (the page/fragment immediately before the current page/fragment) will be displayed.
This is the code for the ToolBar, DrawerLayout, NavigationView and getSupportActionBar():
final DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
final NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
android.support.v7.widget.Toolbar toolbar = (android.support.v7.widget.Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbar.setVisibility(View.VISIBLE);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setLogo(R.mipmap.ic_launcher);
getSupportActionBar().setDisplayUseLogoEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
I am unable to use ActionBar. For some reason (I don't know why), my Android studio/ program, will not allow me to use the ActionBar. So I am substituting that with the set/getSupportActionBar().
The function used in relation to this are:
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_settings, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
switch (id) {
case android.R.id.home:
onBackPressed();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
My activity_main.xml file is:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
android:id="#+id/activity_main"
android:orientation="vertical"
tools:openDrawer="start"
tools:context="com.example.albin.settings_menu.SettingsActivity">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#fff">
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
app:popupTheme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:title="Settings"/>
<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">
<FrameLayout
android:id="#+id/frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/toolbar">
</FrameLayout>
<android.support.design.widget.NavigationView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
android:layout_marginTop="-24dp"
app:menu="#menu/options_menu" />
</android.support.v4.widget.DrawerLayout>
</RelativeLayout>
</LinearLayout>
The problem is that I don't know which is the useful code, which is the useless code and how to mix/join/(add additional codes to) these (codes, methods, variables/objects, fragments, xml layouts) to get the desired outcome, that is, the application of a back button on the action bar/tool bar.
Most of the code above is implemented for the up button, not the back button. I have read at several places that up and back buttons are not the same.
I tried several links on internet as well as on this site, but none of them has just what I need.
Hope someone can give me an clear answer...
You can include the back icon in ToolBar:
Initialize ToolBar:
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
You can use an drawable icon as a back button.
toolbar.setNavigationIcon(R.drawable.your_drawable_icon);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// what do you want here
}
});
If you do not want to use drawable icon then:
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// what do you want here
}
});
Actually your layout having that issue because you have added toolbar in RelativeLayout so drawer layout is overlapping on it that's why you would not able to click on back arrow, i have fix your layout see below
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
app:navigationIcon="#drawable/ic_back_black"
app:popupTheme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:title="Settings" />
<android.support.v4.widget.DrawerLayout
android:id="#+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/frame"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/toolbar" />
<android.support.design.widget.NavigationView
android:id="#+id/nav_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:menu="#menu/options_menu" />
</android.support.v4.widget.DrawerLayout>
</LinearLayout>
The simplest way would be to add parent activity in manifest file as developer docs suggest.
<activity
android:name=".ChildActivity"
android:parentActivityName=".ParentActivity" >
and java code you already have done it, setSupportActionbar and setHomeAsUpEnabled.
Edited :
its necessary to add up action for icon to be visible, as mentioned in
Android Developer Docs
So toolbar gives added flexibility to modify title-bar in Android.
As far as why getActionBar is not working and you are compelled to use getSupportActionBar is because you must be using SupportLibrary. SupportLibrary gives backward compatibility to earlier SDK versions.
If you want to modify your title-bar/header/action-bar extensively
then use toolbar otherwise use action-bar.
Add a navigation click listener to your toolbar , like below
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onBackPressed();
}
});
If you are referencing some actions from the action bar, such as a Save action or a Share one, and you are overriding onOptionsItemSelected method, then you need to define the behavior when the back or home button is clicked:
#Override public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_save:
//save stuff
break;
//this is what you need to add to reference again back/home button
case android.R.id.home:
//do your stuff here, usually back to the home or close the current activity
getActivity().finish();
break;
default:
break;
}
return true;

How to disable manual sliding-out of navigation view

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);

Spinner in the toolbar appears when I search - Android Lollipop

I have a drawer navigation and I switch between fragments, in the Fragment ONE I have a spinner in the toolbar. In the Fragment TWO, I don't want the spinner, so I remove the spinner with the property "visibility=GONE" and that works.
BUT, in the Fragment TWO, doing the following steps, something strange really happens
Tap in the search icon
The search view appears in the toolbar
I tap cancel
The search view collapse, and the spinner from the Fragment ONE shows up
I have tried to use this listener "OnActionExpandListener" in the search icon to hide the spinner again when user taps cancel, but it doesn't work.
any ideas?
Drawer navigation where I set up the toolbar
<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:fitsSystemWindows="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<include layout="#layout/toolbar_dropdown"/>
<!-- The main content view -->
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
<!-- The navigation drawer -->
<ListView android:id="#+id/left_drawer"
android:fitsSystemWindows="true"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:layout_marginTop="56dp"
android:choiceMode="singleChoice"
android:divider="#color/gray_light_divider_list_drawerNav"
android:dividerHeight="1dp"
android:background="#color/gray_light_background_list_drawerNav"
/>
Drawer navigation Activity method OnCreate, where I setup the the toolbar
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
if (toolbar != null) {
setSupportActionBar(toolbar);
}
if(getSupportActionBar()!=null) {
getSupportActionBar().setDisplayShowTitleEnabled(false);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setHomeButtonEnabled(true);
}
This is how I switch between fragments
android.support.v4.app.FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.content_frame, fragment);
transaction.addToBackStack(null);
transaction.commit();
Using the ActionBarDrawerToggle in the method onDrawerOpened, I remove the spinner, so that means that every time the Drawer Navigation is open I removed the spinner like this
Spinner spinner = (Spinner)findViewById(R.id.spinner_nav);
spinner.setVisibility(View.GONE);
This is the OnActionExpandListener in the Fragment TWO
MenuItemCompat.OnActionExpandListener searchOnActionExpandListener = new MenuItemCompat.OnActionExpandListener()
{
#Override
public boolean onMenuItemActionExpand(MenuItem menuItem) {
return true;
}
#Override
public boolean onMenuItemActionCollapse(MenuItem menuItem) {
Spinner spinner = (Spinner)findViewById(R.id.spinner_nav);
spinner.setVisibility(View.GONE);
return true;
}
};
To resolve this issue, I did the following.
I removed the spinner in the toolbar so it looks like this
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/actionBarSize"
app:theme="#style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
android:background="?attr/colorPrimary">
</android.support.v7.widget.Toolbar>
And I started to add the spinner in the fragment ONE programatically
Toolbar toolbar = (Toolbar)getActivity().findViewById(R.id.toolbar);
if(toolbar.findViewWithTag("spinner_nav")==null) {
Spinner spinner = new Spinner(getActivity());
spinner.setTag("spinner_nav");
//Setting up the adapter
AdapterFragmentOne spinnerAdapter = new AdapterFragmentOne(getActivity(), array);
spinnerAdapter.setDropDownViewResource(R.layout.spinner_dropdown_item);
if (spinner != null) {
spinner.setVisibility(View.VISIBLE);
spinner.setAdapter(spinnerAdapter);
}
spinnerAdapter.notifyDataSetChanged();
spinner.setOnItemSelectedListener(mOnNavigationListener);
toolbar.addView(spinner);
}
In my Drawer navigation Activity I remove the spinner when the drawer is opened, I execute
//Removing the spinner view
Spinner spinner = (Spinner) toolbar.findViewWithTag("spinner_nav");
toolbar.removeView(spinner);

Same Navigation Drawer in different Activities

I made a working navigation drawer like it's shown in the tutorial on the developer.android.com website. But now, I want to use one Navigation Drawer, i created in the NavigationDrawer.class for multiple Activities in my Application.
My question is, if anyone here can make a little Tutorial, which explains, how to use one Navigation drawer for multiple Activities.
I read it first at this Answer
Android Navigation Drawer on multiple Activities
but it didn't work on my Project
public class NavigationDrawer extends Activity {
public DrawerLayout drawerLayout;
public ListView drawerList;
private ActionBarDrawerToggle drawerToggle;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
drawerToggle = new ActionBarDrawerToggle((Activity) this, drawerLayout, R.drawable.ic_drawer, 0, 0) {
public void onDrawerClosed(View view) {
getActionBar().setTitle(R.string.app_name);
}
public void onDrawerOpened(View drawerView) {
getActionBar().setTitle(R.string.menu);
}
};
drawerLayout.setDrawerListener(drawerToggle);
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);
listItems = getResources().getStringArray(R.array.layers_array);
drawerList = (ListView) findViewById(R.id.left_drawer);
drawerList.setAdapter(new ArrayAdapter<String>(this, R.layout.drawer_list_item, android.R.id.text,
listItems));
drawerList.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int pos, long arg3) {
drawerClickEvent(pos);
}
});
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (drawerToggle.onOptionsItemSelected(item)) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
drawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
drawerToggle.onConfigurationChanged(newConfig);
}
}
In this Activity i want to have the Navigation Drawer so I extends 'NavigationDrawer' and in some other Activities i want to User the Same Navigation drawer
public class SampleActivity extends NavigationDrawer {...}
If you want a navigation drawer, you should use fragments.
I followed this tutorial last week and it works great:
http://developer.android.com/training/implementing-navigation/nav-drawer.html
You can also download sample code from this tutorial, to see how you can do this.
Without fragments:
This is your BaseActivity Code:
public class BaseActivity extends Activity
{
public DrawerLayout drawerLayout;
public ListView drawerList;
public String[] layers;
private ActionBarDrawerToggle drawerToggle;
private Map map;
protected void onCreate(Bundle savedInstanceState)
{
// R.id.drawer_layout should be in every activity with exactly the same id.
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
drawerToggle = new ActionBarDrawerToggle((Activity) this, drawerLayout, R.drawable.ic_drawer, 0, 0)
{
public void onDrawerClosed(View view)
{
getActionBar().setTitle(R.string.app_name);
}
public void onDrawerOpened(View drawerView)
{
getActionBar().setTitle(R.string.menu);
}
};
drawerLayout.setDrawerListener(drawerToggle);
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);
layers = getResources().getStringArray(R.array.layers_array);
drawerList = (ListView) findViewById(R.id.left_drawer);
View header = getLayoutInflater().inflate(R.layout.drawer_list_header, null);
drawerList.addHeaderView(header, null, false);
drawerList.setAdapter(new ArrayAdapter<String>(this, R.layout.drawer_list_item, android.R.id.text1,
layers));
View footerView = ((LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(
R.layout.drawer_list_footer, null, false);
drawerList.addFooterView(footerView);
drawerList.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int pos, long arg3) {
map.drawerClickEvent(pos);
}
});
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (drawerToggle.onOptionsItemSelected(item)) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
drawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
drawerToggle.onConfigurationChanged(newConfig);
}
}
All the other Activities that needs to have a navigation drawer should extend this Activity instead of Activity itself, example:
public class AnyActivity extends BaseActivity
{
//Because this activity extends BaseActivity it automatically has the navigation drawer
//You can just write your normal Activity code and you don't need to add anything for the navigation drawer
}
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">
<!-- The main content view -->
<FrameLayout
android:id="#+id/content_frame"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- Put what you want as your normal screen in here, you can also choose for a linear layout or any other layout, whatever you prefer -->
</FrameLayout>
<!-- The navigation drawer -->
<ListView android:id="#+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:choiceMode="singleChoice"
android:divider="#android:color/transparent"
android:dividerHeight="0dp"
android:background="#111"/>
</android.support.v4.widget.DrawerLayout>
Edit:
I experienced some difficulties myself, so here is a solution if you get NullPointerExceptions. In BaseActivity change the onCreate function to protected void onCreateDrawer(). The rest can stay the same. In the Activities which extend BaseActivity put the code in this order:
super.onCreate(savedInstanceState);
setContentView(R.layout.activity);
super.onCreateDrawer();
This is how you can create a navigation drawer with multiple activities, if you have any questions feel free to ask.
Edit 2:
As said by #GregDan your BaseActivity can also override setContentView() and call onCreateDrawer there:
#Override
public void setContentView(#LayoutRes int layoutResID)
{
super.setContentView(layoutResID);
onCreateDrawer() ;
}
I've found the best implementation. It's in the Google I/O 2014 app.
They use the same approach as Kevin's. If you can abstract yourself from all unneeded stuff in I/O app, you could extract everything you need and it is assured by Google that it's a correct usage of navigation drawer pattern.
Each activity optionally has a DrawerLayout as its main layout. The interesting part is how the navigation to other screens is done. It is implemented in BaseActivity like this:
private void goToNavDrawerItem(int item) {
Intent intent;
switch (item) {
case NAVDRAWER_ITEM_MY_SCHEDULE:
intent = new Intent(this, MyScheduleActivity.class);
startActivity(intent);
finish();
break;
This differs from the common way of replacing current fragment by a fragment transaction. But the user doesn't spot a visual difference.
So this answer is a few years late but someone may appreciate it. Android has given us a new widget that makes using one navigation drawer with several activities easier.
android.support.design.widget.NavigationView is modular and has its own layout in the menu folder. The way that you use it is to wrap xml layouts the following way:
Root Layout is a android.support.v4.widget.DrawerLayout that contains two children: an <include ... /> for the layout that is being wrapped (see 2) and a android.support.design.widget.NavigationView.
<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" />
nav_header_main is just a LinearLayout with orientation = vertical for the header of your Navigation Drawar.
activity_main_drawer is a menu xml in your res/menu directory. It can contain items and groups of your choice. If you use the AndroidStudio Gallery the wizard will make a basic one for you and you can see what your options are.
App bar layout is usually now a android.support.design.widget.CoordinatorLayout and this will include two children: a android.support.design.widget.AppBarLayout (which contains a android.support.v7.widget.Toolbar) and an <include ... > for your actual content (see 3).
<android.support.design.widget.CoordinatorLayout
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="yourpackage.MainActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/AppTheme.PopupOverlay" />
</android.support.design.widget.AppBarLayout>
<include layout="#layout/content_main" />
Content layout can be whatever layout you want. This is the layout that contains the main content of the activity (not including the navigation drawer or app bar).
Now, the cool thing about all of this is that you can wrap each activity in these two layouts but have your NavigationView (see step 1) always point to activity_main_drawer (or whatever). This means that you will have the same(*) Navigation Drawer on all activities.
They won't be the same instance of NavigationView but, to be fair, that wasn't possible even with the BaseActivity solution outlined above.
Easiest way to reuse a common Navigation drawer among a group of activities
app_base_layout.xml
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<FrameLayout
android:id="#+id/view_stub"
android:layout_width="match_parent"
android:layout_height="match_parent">
</FrameLayout>
<android.support.design.widget.NavigationView
android:id="#+id/navigation_view"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
app:menu="#menu/menu_test"
/>
</android.support.v4.widget.DrawerLayout>
AppBaseActivity.java
/*
* This is a simple and easy approach to reuse the same
* navigation drawer on your other activities. Just create
* a base layout that conains a DrawerLayout, the
* navigation drawer and a FrameLayout to hold your
* content view. All you have to do is to extend your
* activities from this class to set that navigation
* drawer. Happy hacking :)
* P.S: You don't need to declare this Activity in the
* AndroidManifest.xml. This is just a base class.
*/
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.design.widget.NavigationView;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
public abstract class AppBaseActivity extends AppCompatActivity implements MenuItem.OnMenuItemClickListener {
private FrameLayout view_stub; //This is the framelayout to keep your content view
private NavigationView navigation_view; // The new navigation view from Android Design Library. Can inflate menu resources. Easy
private DrawerLayout mDrawerLayout;
private ActionBarDrawerToggle mDrawerToggle;
private Menu drawerMenu;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
super.setContentView(R.layout.app_base_layout);// The base layout that contains your navigation drawer.
view_stub = (FrameLayout) findViewById(R.id.view_stub);
navigation_view = (NavigationView) findViewById(R.id.navigation_view);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, 0, 0);
mDrawerLayout.setDrawerListener(mDrawerToggle);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
drawerMenu = navigation_view.getMenu();
for(int i = 0; i < drawerMenu.size(); i++) {
drawerMenu.getItem(i).setOnMenuItemClickListener(this);
}
// and so on...
}
#Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
mDrawerToggle.syncState();
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
mDrawerToggle.onConfigurationChanged(newConfig);
}
/* Override all setContentView methods to put the content view to the FrameLayout view_stub
* so that, we can make other activity implementations looks like normal activity subclasses.
*/
#Override
public void setContentView(int layoutResID) {
if (view_stub != null) {
LayoutInflater inflater = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
View stubView = inflater.inflate(layoutResID, view_stub, false);
view_stub.addView(stubView, lp);
}
}
#Override
public void setContentView(View view) {
if (view_stub != null) {
ViewGroup.LayoutParams lp = new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
view_stub.addView(view, lp);
}
}
#Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
if (view_stub != null) {
view_stub.addView(view, params);
}
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Pass the event to ActionBarDrawerToggle, if it returns
// true, then it has handled the app icon touch event
if (mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
// Handle your other action bar items...
return super.onOptionsItemSelected(item);
}
#Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.item1:
// handle it
break;
case R.id.item2:
// do whatever
break;
// and so on...
}
return false;
}
}
For anyone else looking to do what the original poster is asking, please consider to use fragments instead the way Kevin said. Here is an excellent tutorial on how to do that:
https://github.com/codepath/android_guides/wiki/Fragment-Navigation-Drawer
If you choose to instead use activities instead of fragments you are going to run into the problem of the nav drawer being re-created every time you navigate to a new activity. This results in an ugly/slow rendering of the nav drawer each time.
My suggestion is: do not use activities at all, instead use fragments, and replace them in the container (Linear Layout for example) where you show your first fragment. [Note: you can use this concept using the navigation graph. Compose further reduces the need to make your layout XMLs, so we can apply this there too.]
The code is available in Android Developer Tutorials, you just have to customize.
http://developer.android.com/training/implementing-navigation/nav-drawer.html
It is advisable that you should use more and more fragments in your application, and there should be only four basic activities local to your application, that you mention in your AndroidManifest.xml apart from the external ones (FacebookActivity for example):
SplashActivity: uses no fragment, and uses FullScreen theme.
LoginSignUpActivity: Do not require NavigationDrawer at all, and no back button as well, so simply use the normal toolbar, but at the least, 3 or 4 fragments will be required. Uses no-action-bar theme
HomeActivity or DashBoard Activity: Uses no-action-bar theme. Here you require Navigation drawer, also all the screens that follow will be fragments or nested fragments, till the leaf view, with the shared drawer. All the settings, user profile and etc. will be here as fragments, in this activity.
The fragments here will not be added to the back stack and will be opened from the drawer menu items. In the case of fragments that require back button instead of the drawer, there is a fourth kind of activity below.
Activity without drawer. This activity has a back button on top and the fragments inside will be sharing the same action-bar. These fragments will be added to the back-stack, as there will be a navigation history.
[ For further guidance see: https://stackoverflow.com/a/51100507/787399 ]
Happy Coding !!
update this code in baseactivity. and dont forget to include drawer_list_header in your activity xml.
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_ACTION_BAR_OVERLAY);
setContentView(R.layout.drawer_list_header);
and dont use request() in your activity. but still the drawer is not visible on clicking image..and by dragging it will visible without list items. i tried a lot but no success. need some workouts for this...
With #Kevin van Mierlo 's answer, you are also capable of implementing several drawers. For instance, the default menu located on the left side (start), and a further optional menu, located on the right side, which is only shown when determinate fragments are loaded.
I've been able to do that.
package xxxxxx;
import android.app.SearchManager;
import android.content.Context;
import android.content.Intent;
import android.widget.SearchView;
import android.support.design.widget.NavigationView;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
public class loginhome extends AppCompatActivity {
private Toolbar toolbar;
private NavigationView navigationView;
private DrawerLayout drawerLayout;
// Make sure to be using android.support.v7.app.ActionBarDrawerToggle version.
// The android.support.v4.app.ActionBarDrawerToggle has been deprecated.
private ActionBarDrawerToggle drawerToggle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.loginhome);
// Initializing Toolbar and setting it as the actionbar
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
//Initializing NavigationView
navigationView = (NavigationView) findViewById(R.id.nav_view);
//Setting Navigation View Item Selected Listener to handle the item click of the navigation menu
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
// This method will trigger on item Click of navigation menu
public boolean onNavigationItemSelected(MenuItem menuItem) {
//Checking if the item is in checked state or not, if not make it in checked state
if(menuItem.isChecked()) menuItem.setChecked(false);
else menuItem.setChecked(true);
//Closing drawer on item click
drawerLayout.closeDrawers();
//Check to see which item was being clicked and perform appropriate action
switch (menuItem.getItemId()){
//Replacing the main content with ContentFragment Which is our Inbox View;
case R.id.nav_first_fragment:
Toast.makeText(getApplicationContext(),"First fragment",Toast.LENGTH_SHORT).show();
FirstFragment fragment = new FirstFragment();
android.support.v4.app.FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frame,fragment);
fragmentTransaction.commit();
return true;
// For rest of the options we just show a toast on click
case R.id.nav_second_fragment:
Toast.makeText(getApplicationContext(),"Second fragment",Toast.LENGTH_SHORT).show();
SecondFragment fragment2 = new SecondFragment();
android.support.v4.app.FragmentTransaction fragmentTransaction2 = getSupportFragmentManager().beginTransaction();
fragmentTransaction2.replace(R.id.frame,fragment2);
fragmentTransaction2.commit();
return true;
default:
Toast.makeText(getApplicationContext(),"Somethings Wrong",Toast.LENGTH_SHORT).show();
return true;
}
}
});
// Initializing Drawer Layout and ActionBarToggle
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle actionBarDrawerToggle = new ActionBarDrawerToggle(this,drawerLayout,toolbar,R.string.drawer_open, R.string.drawer_close){
#Override
public void onDrawerClosed(View drawerView) {
// Code here will be triggered once the drawer closes as we dont want anything to happen so we leave this blank
super.onDrawerClosed(drawerView);
}
#Override
public void onDrawerOpened(View drawerView) {
// Code here will be triggered once the drawer open as we dont want anything to happen so we leave this blank
super.onDrawerOpened(drawerView);
}
};
//Setting the actionbarToggle to drawer layout
drawerLayout.setDrawerListener(actionBarDrawerToggle);
//calling sync state is necessay or else your hamburger icon wont show up
actionBarDrawerToggle.syncState();
}
use this for your toolbar.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimary"
android:elevation="4dp"
android:id="#+id/toolbar"
android:theme="#style/ThemeOverlay.AppCompat.Dark"
>
</android.support.v7.widget.Toolbar>
use this for navigation header if want to use
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="192dp"
android:background="?attr/colorPrimaryDark"
android:padding="16dp"
android:theme="#style/ThemeOverlay.AppCompat.Dark"
android:orientation="vertical"
android:gravity="bottom">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="56dp"
android:id="#+id/navhead"
android:orientation="vertical"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true">
<TextView
android:id="#+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:textColor="#ffffff"
android:text="tanya"
android:textSize="14sp"
android:textStyle="bold"
/>
<TextView
android:id="#+id/email"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#ffffff"
android:layout_marginLeft="16dp"
android:layout_marginTop="5dp"
android:text="tanya.com"
android:textSize="14sp"
android:textStyle="normal"
/>
</LinearLayout>
<de.hdodenhof.circleimageview.CircleImageView
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_below="#+id/imageView"
android:layout_marginTop="15dp"
android:src="#drawable/face"
android:id="#+id/circleView"
/>
</RelativeLayout>
I do it in Kotlin like this:
open class BaseAppCompatActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
protected lateinit var drawerLayout: DrawerLayout
protected lateinit var navigationView: NavigationView
#Inject
lateinit var loginService: LoginService
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.d("BaseAppCompatActivity", "onCreate()")
App.getComponent().inject(this)
drawerLayout = findViewById(R.id.drawer_layout) as DrawerLayout
val toolbar = findViewById(R.id.toolbar) as Toolbar
setSupportActionBar(toolbar)
navigationView = findViewById(R.id.nav_view) as NavigationView
navigationView.setNavigationItemSelectedListener(this)
val toggle = ActionBarDrawerToggle(this, drawerLayout, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close)
drawerLayout.addDrawerListener(toggle)
toggle.syncState()
toggle.isDrawerIndicatorEnabled = true
val navigationViewHeaderView = navigationView.getHeaderView(0)
navigationViewHeaderView.login_txt.text = SharedKey.username
}
private inline fun <reified T: Activity> launch():Boolean{
if(this is T) return closeDrawer()
val intent = Intent(applicationContext, T::class.java)
startActivity(intent)
finish()
return true
}
private fun closeDrawer(): Boolean {
drawerLayout.closeDrawer(GravityCompat.START)
return true
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
val id = item.itemId
when (id) {
R.id.action_tasks -> {
return launch<TasksActivity>()
}
R.id.action_contacts -> {
return launch<ContactActivity>()
}
R.id.action_logout -> {
createExitDialog(loginService, this)
}
}
return false
}
}
Activities for drawer must inherit this BaseAppCompatActivity, call super.onCreate after content is set (actually, can be moved to some init method) and have corresponding elements for ids in their layout
My answer is just a conceptual one without any source code. It might be useful for some readers like myself to understand.
It depends on your initial approach on how you architecture your app. There are basically two approaches.
You create one activity (base activity) and all the other views and screens will be fragments. That base activity contains the implementation for Drawer and Coordinator Layouts. It is actually my preferred way of doing because having small self-contained fragments will make app development easier and smoother.
If you have started your app development with activities, one for each screen , then you will probably create base activity, and all other activity extends from it. The base activity will contain the code for drawer and coordinator implementation. Any activity that needs drawer implementation can extend from base activity.
I would personally prefer avoiding to use fragments and activities mixed without any organizing. That makes the development more difficult and get you stuck eventually. If you have done it, refactor your code.
It is elaborated in the following video tutorial
Navigation Drawer on Multiple Activities Using Base Activity
It is very easy to make a base navigation drawer activity and extend that base navigation drawer activity to all those activities on which you want to display navigation drawer,
Make navigation menu, header
create a base activity for navigation drawer
create a content layout
Combined menu, header, content layout on base activity
By using frame layout, insert every activity in the drawer menu.
All steps are clearly explained in the video
Create Navigation drawer in your MainActivity using fragment.
Initialize the Navigation Drawer in MainActivity
now in all other activities you want to use same Navigation Drawer put DrawerLayout as base and fragment as navigation drawer. Just set android:name in your fragment pointing to your fragment Java file. You won't need to initialize the fragment in other Activities.
You can access Nav Drawer by swipe in other activities like in Google Play Store app

How to set Navigation Drawer to be opened from right to left

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"

Categories

Resources