212

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 {...}
MEX
  • 2,664
  • 5
  • 22
  • 28

13 Answers13

189

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() ;
}
starball
  • 20,030
  • 7
  • 43
  • 238
Kevin van Mierlo
  • 9,554
  • 5
  • 44
  • 76
  • I Made a working Navigation drawer, but now I want to Use one Navigation drawer in multiple activities – MEX Oct 19 '13 at 11:21
  • The way to go is to use fragments instead of activities. I can't think of any reason why you want to use activities over fragments. – Kevin van Mierlo Oct 21 '13 at 06:53
  • 8
    I don't want to use activitys over fragments, I just want to use different activitys which uses all the same navigation drawer. I want activity, because there I can use different types of layout like swipe view, map view... – MEX Oct 21 '13 at 13:24
  • 138
    Having just one Activity can be a daunting task for any fairly complex app. Using Activities gives you a lot of free things from the system - so it is a valid point how to use multiple Activities. I can't imagine one Activity handling communication between any number of fragment combinations - it's just not gonna work. – slott Nov 07 '13 at 09:39
  • 1
    I'm sorry it took so long for me to answer. I Edited my answer. I believe this is the tutorial you were looking for. Hope this helps. – Kevin van Mierlo Dec 02 '13 at 11:07
  • do not know why this answer was accepted but extending main class does not do the task. It does not slide out. – Rishabh Srivastava Jan 23 '14 at 06:10
  • @RishabhSrivastava I don´t know what you did, but you did something wrong. This worked for me and for Mex and probably more people. Did you follow my tutorial correctly? You have to write an activity class: BaseActivity. And the Activity classes you want in your app need to extend BaseActivity. Thats all there is to it. – Kevin van Mierlo Jan 23 '14 at 17:00
  • Ok it worked but the list set in the baseactivity does not show up here in AnyActivity....why? – Rishabh Srivastava Jan 24 '14 at 05:30
  • Make a new question and link me to it. I need to see your code. – Kevin van Mierlo Jan 24 '14 at 08:22
  • 2
    @KevinvanMierlo can you tell me what you mean by: R.id.drawer_layout should be in every activity with exactly the same id. Because I did exactly what you told here and I get a NullPointerException in onCreate() method of the Activity that extends this BaseActivity.. – Loolooii Feb 19 '14 at 22:17
  • @Loolooii You make a drawerlayout in the layout file of your activity and you give this the id "drawer_layout" – Kevin van Mierlo Feb 20 '14 at 15:29
  • @KevinvanMierlo I do exactly that and I think it should work now, but it doesn't. When I click on the drawer icon the drawer does not show. I don't get any errors whatsoever. Do you know why? – Loolooii Feb 21 '14 at 20:07
  • 1
    @KevinvanMierlo btw, I think you forgot these 2 lines? super.onCreate(savedInstanceState); setContentView(R.layout.activity_base); – Loolooii Feb 21 '14 at 20:09
  • 1
    @KevinvanMierlo how do I keep the layout of my activity and add this drawerLayout into that? Because both activities require me to set a contentView.. And the layout of my activity overrides the layout of the drawer. Can you explain that part please? – Loolooii Feb 22 '14 at 14:17
  • OK, create a new question and link that question to me or put your code online and link that to me. I don't know whats not working untill I see your code. – Kevin van Mierlo Feb 23 '14 at 09:19
  • @KevinvanMierlo How can i move from one activity to another while i click the item in **Drawer list** – Yugesh Feb 27 '14 at 07:04
  • @Yugesh set setOnItemClickListener on drawerList and from there start your new activity (`Intent myIntent = new Intent(CurrentActivity.this, NextActivity.class); CurrentActivity.this.startActivity(myIntent);`) – Kevin van Mierlo Feb 27 '14 at 09:02
  • Hi Kevin, I've followed your instructions and it's crashing. I've posted a question, I'd appreciate a lot if you could help me out! :) http://stackoverflow.com/questions/22137283/extending-navigation-drawer-activity-to-other-activities – user1627990 Mar 03 '14 at 01:41
  • What if you are extending a fragmentActivity for a viewpager already, how do you go about implementing this... I was originally just including the same code in both my Home activity and my other activity, the problem is that from my other activity with the viewpager I could not click on any items - is that an issue that can be fixed or try to use this method but in that case how to implement it? – Lion789 Mar 05 '14 at 18:47
  • @Lion789 I think if you want that your base activity needs to extend fragmentActivity or else nothing will work. For the rest I'm not sure if something could cause issues. If you still have issues, make a question and link me to it, cause then I need to see some code. – Kevin van Mierlo Mar 06 '14 at 08:20
  • @slott I am trying to do just that, a single activity architecture. I definitely feel that I am getting bogged down. The dilemma, though, is that fragments load in so much faster than launching new activities. – theblang May 15 '14 at 20:33
  • Loads faster than launching new activities ??? - You must be doing something wrong. Any activity should start instantly and then you do the heavy lifting using background tasks while showing a spinner or whatever makes sense for your app. I've made countless apps and never had problems with slow activities. – slott May 17 '14 at 20:01
  • @KevinvanMierlo : Just a quesiotn, for implementing navigation drawer as i understood - Am i supposed to have only one activity and all other as fragments in my whole app ? – Shumail Jul 02 '14 at 21:34
  • @ShumailMohy-ud-Din That is recommended by google. But as slott said, if you have a complex app this might not be the right way. For smaller apps one activity and only fragments should be fine. – Kevin van Mierlo Jul 14 '14 at 11:00
  • @KevinvanMierlo Thankyou - Yeah for complex that's seriously a mess. I am trying to do with activities – Shumail Jul 14 '14 at 17:04
  • @KevinvanMierlo Can you please post the XML layout for BaseActivity and AnyActivity? That would be very helpful! – Price Aug 05 '14 at 19:28
  • @user87049 XML layout added. BaseActivity doesn't have a layout. Just make sure to add drawer_layout in every activity and extend BaseActivity in every Activity. – Kevin van Mierlo Aug 06 '14 at 10:33
  • Can we make it without the same `XML` in every `Activity` layout? – levi Aug 20 '14 at 22:14
  • @levi Yeah, the drawer layout part and the listview part should be in every activity. The framelayout can be any layout you want and this is the layout for your screen. You can change this in the way you like – Kevin van Mierlo Aug 25 '14 at 15:15
  • 1
    @KevinvanMierlo I'm using Android Studio and pasted the BaseActivity code, but am running up against symbols not being able to be resolved such as ic_drawer, menu, layers_array, drawer_list_header, drawer_list_item, drawer_list_footer, and the drawerClickEvent() as well If the BaseActivity doesn't require a layout how do I resolve these errors? – Kurt Wagner Aug 27 '14 at 20:59
  • 1
    @KurtWagner This BaseActivity was specific for the question, here is the code for everybody to use: https://gist.github.com/kevinvanmierlo/c1a0d6b8bed65b1eeaa6 ic_drawer is an icon provided in the actionbar pack: developer.android.com/downloads/design/Android_Design_Icons_20130926.zip (ic_drawer is the image, three stripes, next to the logo if a navigation drawer is available) – Kevin van Mierlo Aug 29 '14 at 13:11
  • @KevinvanMierlo drawer layout is appering only by dragging.. on click image is not working... and list is not visible. – M S Gadag Nov 08 '14 at 08:32
  • @MSGadag I'm not sure why list is not visible, but for the on click image check this: http://developer.android.com/training/implementing-navigation/nav-drawer.html#ActionBarIcon This is from the android website that walks you through how to get the on click on a drawerlayout. If you can't manage to make the list working create a new question and link me to that question, I will help you – Kevin van Mierlo Nov 08 '14 at 15:38
  • @slott I don't agree with you. this is not about communication between activities. this is inheritance. all of activities and it's components even naviagation drawer is alive but with a same parent. – David Jun 27 '15 at 11:59
  • @KevinvanMierlo Can you please post snippet of main_activity.xml too? Thanks! – Hamed MP Jul 12 '15 at 11:17
  • @HamedMP The xml is the post snippet of main_activity.xml. In the FrameLayout (content_frame) you put your normal layout. I just stripped that because it's irrelevant for the answer. Just to be clear, the BaseActivity doesn't have an xml file. – Kevin van Mierlo Jul 13 '15 at 07:13
  • Better solution is to `@Override public void setContentView(@LayoutRes int layoutResID) { super.setContentView(layoutResID); onCreateDrawer() }` – Greg Dan Oct 29 '15 at 13:40
  • @GregDan Good solution! Added it to my answer. – Kevin van Mierlo Oct 29 '15 at 14:59
  • It works good.I have a doubt.Actually should we add drawer layout and listview in the child activity's layout also? – Sharath Nov 08 '15 at 10:29
  • @Sharanth yes those layouts should be added to the child activity. You could put the list view in a separate layout or make the drawer a fragment so you don't have to add everything everything you want an activity with a drawer – Kevin van Mierlo Nov 08 '15 at 11:00
  • @slott You can use EventBus for all your communications. – syloc Jan 06 '16 at 13:24
  • Yes EventBus is a real game changer when it comes to communication across fragments and activities. – slott Jan 06 '16 at 16:10
  • 1
    I try to use this solution but I have a problem on this line: `drawerToggle = new ActionBarDrawerToggle((Activity) this, drawerLayout, R.drawable.ic_drawer, 0, 0)` where AS says it is specting a toolbar on the third parameter and R.drawable.ic_drawer is an int. How can I solve it? – Pau Arlandis Martinez Mar 15 '16 at 16:40
  • @PauArlandisMartinez The new `ActionBarDrawerToggle` doesn't need a drawable anymore, so you have two options: Use the `ActionBarDrawerToggle` with an `ActionBar` or with a `Toolbar`. Example using `ActionBar`: `drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, 0, 0);`. Example with `Toolbar`: `drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, toolbar, 0, 0);`. The two zeros on the end should be a String located in the strings.xml. – Kevin van Mierlo Mar 16 '16 at 09:55
  • 1
    @KevinvanMierlo ok, but if I use the actionBar solution I need to import android.support.v4.app.ActionBarDrawerToggle and If I use the toolbar solution I need to import android.support.v7.app.ActionBarDrawerToggle. It's important to have this in mind. Also the actionBar solution is deprecated today. – Pau Arlandis Martinez Mar 17 '16 at 11:18
  • 1
    @PauArlandisMartinez No you should use `android.support.v7.app.ActionBarDrawerToggle`. You can leave out toolbar and I think it should work then. But the `ActionBar` in general is deprecated now, so you should think about the `Toolbar` solution. – Kevin van Mierlo Mar 17 '16 at 13:40
  • sir, i used the same with extending BaseActivity but on back pressed this navigation doesn't work. Please help – Pihu May 04 '16 at 09:26
  • @PriyankaMinhas Can you create a new question? I don't want to overload this answer with comments. In that question you could give me some more details and the code you're using. – Kevin van Mierlo May 04 '16 at 09:48
  • Here is it - http://stackoverflow.com/questions/37024908/navigation-drawer-doesnt-work-onbackpressed-in-different-activities – Pihu May 04 '16 at 10:21
  • @KevinvanMierlo I get null pointer exceptions when the `onCreateDrawer` method tries to operate on the `drawer`. Because the drawer xml is in the layout of the base activity (dashboard activity in my case), it isn't available in subsequent activities extending the base activity. How should the XML be arranged? I was going to abstract the drawer into a separate layout file but based on how the drawer needs to wrap the rest of the content I'm not sure how to accomplish that. – justinraczak Oct 05 '16 at 14:34
  • @KevinvanMierlo I created a separate question here: http://stackoverflow.com/questions/39878380/how-to-use-nav-drawer-in-multiple-activities – justinraczak Oct 05 '16 at 15:48
  • Where are you using `content_frame`? – Denny Nov 10 '16 at 18:39
  • @Denny `content_frame` is the regular layout you normally put the screen in. So if you want to show an image on that page you need to put the `ImageView` inside the `content_frame`. It could also be another layout, it's just to clarify that the regular layout should be there. – Kevin van Mierlo Nov 11 '16 at 10:36
  • 1
    After many bugs and difficult situations with fragments I understood that it should better use activities with Navigation drawer. Keyboard events, transparent statusbar, data transfer between fragments and so on. **Don't use fragments!** – CoolMind Nov 18 '16 at 09:08
  • Some people write that activity with fragments creates new fragments faster, also an animation is more friendly (with activities you should create a new activity and then close a drawer). Also I encountered a difficult bug with creating and managing menus. Then I returned to fragments, as they already work :( – CoolMind Dec 01 '16 at 14:31
  • @CoolMind You're right that fragments responds quicker and has more possibilities with animation. But in the end, if you create this code once you can reüse it for every project you have with a NavigationDrawer. Creating menus should be the same as always – Kevin van Mierlo Dec 02 '16 at 08:50
  • @KevinvanMierlo, thanks. First I tried to make with fragments as recommended, but I need different toolbars at different fragments ((a) usual ActionBars and (b) an image from top, behind transparent Statusbar). A similar topic: http://stackoverflow.com/questions/35015182/different-toolbar-for-fragments-and-navigation-drawer. I made one activity with DrawerLayout and NavigationView, having Toolbar and other stuff in fragment. It works not always correctly, especially on new Androids. – CoolMind Dec 02 '16 at 11:50
  • Then I tried to replace with activities and got a problem when tried to replace a toolbar. onCreateOptionsMenu stopped adding menu buttons, onOptionsItemSelected stopped to be called. So many difficult situations, that I returned to fragments again. – CoolMind Dec 02 '16 at 11:50
  • @CoolMind If it does not always work correctly, I don't really know what's going on. You could create another question for that. onCreateOptionsMenu is probably not called because you haven't done `setSupportActionBar` with the `Toolbar`. If this isn't the case you should also create another question. – Kevin van Mierlo Dec 02 '16 at 12:36
  • @KevinvanMierlo, you are right, better create another question. Also will try your code for activities creation. Thanks! – CoolMind Dec 02 '16 at 13:05
  • Cannot resolve method `protected void onCreateDrawer()` in Base activity extend from Activity – Ashik Azeez Jan 24 '19 at 09:41
  • 1
    @AshikAzeez You need to create this method yourself. In the first part of my answer you'll see all drawer related code in the onCreate, but because that gave exceptions I moved the code to a method `onCreateDrawer()`. – Kevin van Mierlo Jan 24 '19 at 12:37
  • @KevinvanMierlo i've place original content inside framelayout . now when i replace it with fragment its overlap to eachother . any workarround ? – Tejas Pandya Feb 19 '19 at 10:18
  • @TejasPandya I don't really know what you mean, but I guess you should replace the fragments so it doesn't overlap and also remove the original view (which is now inside your fragment – Kevin van Mierlo Feb 19 '19 at 12:35
  • I found this awesome page for getting a Kotlin fragment solution going in a hurry. You just need to change `fragmentManager` to `supportFragmentManager` and add `android:id="@+id/content_main"` to the `content_main.xml` layout. All of the changes to the generated template are in `onNavigationItemSelected()`. You'll need to modify it to use the back stack. http://javaant.com/android-navigation-drawer-using-fragment-and-kotlin/#.XNxEUtNKiL4 – Joe Lapp May 15 '19 at 16:55
  • 1
    It's all true with just one BIG problem. Fragments suck in almost every way, especially how they slide in and out. Absolutely NO beauty and STABILITY in that process, a possibility for double-clicking the links, etc. – ekashking Jun 15 '19 at 20:44
35

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.

WindRider
  • 11,958
  • 6
  • 50
  • 57
8

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:

  1. 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.

  1. 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" />
    

  2. 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.
jwehrle
  • 4,414
  • 1
  • 17
  • 13
  • stackoverflow is cutting off some of the enclosing xml brackets but the important stuff is all there. – jwehrle Oct 06 '17 at 22:34
  • but how do you treat functionality like buttons? you must write the same code in every activity? – Laur89 Mar 20 '19 at 12:34
  • Yes, because these are separate instances. However, you can make a super class for your activities to extend and put that code there once. – jwehrle Mar 25 '19 at 19:09
  • @jwehrle can you write an example about making a super class for our activities? – CDrosos May 27 '20 at 08:08
  • public abstract class MyBaseActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener { // implement the following: Override public boolean onNavigationItemSelected(@NonNull MenuItem item) {} } public class MyActivity extends MyBaseActivity {} – jwehrle May 28 '20 at 16:55
  • The formatting is all wrong in the comment section. Define a base class for yourself that extends Activity (in this case, AppCompatActivity) and then all of your regular activities should extend your new base activity. Essentially, you are inserting a class in between your activities and Android's activity class. – jwehrle May 28 '20 at 16:57
8

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;
    }
}
Levon Petrosyan
  • 8,815
  • 8
  • 54
  • 65
6

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.

Micro
  • 10,303
  • 14
  • 82
  • 120
5

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

  1. SplashActivity: uses no fragment, and uses FullScreen theme.

  2. 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

  3. 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.

  4. 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 !!

Abhinav Saxena
  • 1,990
  • 2
  • 24
  • 55
  • This is an older post. You can use fragments to ensure you have one activity always. You keep replacing the fragments in one container dedicated to it. Put in back stack when you need backward navigation, or pop all the fragments when you need a fragment to be shown as the first one. – Abhinav Saxena Jun 15 '16 at 09:49
  • @Cabuxa.Mapache Please check the attached link to my answer for getting further assistance. I have taken a common BaseActivity, which helps sharing ActionBar ToolBar and NavigatonDrawer and other components in all the fragments attached to it. – Abhinav Saxena Jul 05 '18 at 05:42
  • I was curious if you can give me on some input on the app I'm currently building and if what you mentioned above if i should do that in my app. please inbox me thank you. – DCam Jan 12 '23 at 08:41
  • Now that there is a navigation graph and actions (direction to other fragment or activity) concept making that even more easy for you. It supports child fragment for you. Now based on fragments having back button on top, full-screen, with navigation drawer or so, you may design the activities and put your navigation drawer reusing your fragments. – Abhinav Saxena Jan 12 '23 at 09:59
1

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...

M S Gadag
  • 2,057
  • 1
  • 12
  • 15
1

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.

joninx
  • 1,775
  • 6
  • 31
  • 59
1
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>
Volverine
  • 75
  • 10
1

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

Pavlus
  • 1,651
  • 1
  • 13
  • 24
  • I wanted to try your solution but I get this error: "This Activity already has an action bar supplied by the window decor". I want to switch between 3 activities and each other has its own app bar. Do you think that is possible ? – davoid Jan 19 '18 at 12:00
  • I think, you need to move your actionbar to fragments in that case. In our app we used NoActionBar theme and provided toolbar for compatibility, as far as i remember. – Pavlus Jan 20 '18 at 13:35
  • @Pavlus what would the code look like on the second activity? class trackActivity : BaseAppCompatActivity(){ ? – Craig P Aug 30 '18 at 20:50
1

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.

  1. 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.

  2. 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.

Farruh Habibullaev
  • 2,342
  • 1
  • 26
  • 33
0

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,

  1. Make navigation menu, header
  2. create a base activity for navigation drawer
  3. create a content layout
  4. Combined menu, header, content layout on base activity
  5. By using frame layout, insert every activity in the drawer menu.

All steps are clearly explained in the video

-1

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