Sunday 24 August 2014

Android: Navigation Drawer with Multiple activities.


Now a days most of the Android application are using Navigation Drawer/Sliding Drawer like view.
Some of them are using library for doing this. Android has also provided Navigation Drawer to achieve this.
http://developer.android.com/training/implementing-navigation/nav-drawer.html

In this above link we can find demo app to add navigation drawer in our app. But we have to use fragment for achieving this and it is recommend to use fragment.

But in case if we don't want to use fragment or we want to add Navigation Drawer in already existing app which contain activities and we don't want to replace them with fragment.

We can achieve same Navigation Drawer with activities too....I am going to add here demo app to add Navigation Drawer with multiple activities.


First of all we have to create on BaseActivity which will contain layout and all the code related to navigation drawer and then we will use this BaseActivity as parent activity to other activities.

We will extends this BaseActivity  to all the other activities rather than directly extending Activity class in our activities. This way our all the activities will contain same Navigation Drawer without adding any extra code in every activity.

About Code:::

First of all we have to create XML file for adding navigation drawer, we will use this layout xml file in our BaseActivity.

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

    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <ListView
        android:id="@+id/left_drawer"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:background="#111"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp" />
</android.support.v4.widget.DrawerLayout>

As we are already adding layout in BaseActivity we can not add layout in child activity..otherwise it will not work properly so we will add our own layout for the child activity in FrameLayout of above XML.

/* Layout Inflater to add view in frame layout*/
Code Example :: getLayoutInflater().inflate(R.layout.activity_main, frameLayout);
This way we will get our own layout in child activity. Now we can use this as any other normal activity.


BaseActivity.java:

package com.navigation.drawer.activity;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.widget.DrawerLayout;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.FrameLayout;
import android.widget.ListView;
import android.widget.Toast;

/**
 * @author dipenp
 *
 * This activity will add Navigation Drawer for our application and all the code related to navigation drawer.
 * We are going to extend all our other activites from this BaseActivity so that every activity will have Navigation Drawer in it.
 * This activity layout contain one frame layout in which we will add our child activity layout.  
 */
public class BaseActivity extends Activity {

/**
*  Frame layout: Which is going to be used as parent layout for child activity layout.
*  This layout is protected so that child activity can access this
*  */
protected FrameLayout frameLayout;

/**
* ListView to add navigation drawer item in it.
* We have made it protected to access it in child class. We will just use it in child class to make item selected according to activity opened.
*/

protected ListView mDrawerList;

/**
* List item array for navigation drawer items.
* */
protected String[] listArray = { "Item 1", "Item 2", "Item 3", "Item 4", "Item 5" };

/**
* Static variable for selected item position. Which can be used in child activity to know which item is selected from the list.
* */
protected static int position;

/**
*  This flag is used just to check that launcher activity is called first time
*  so that we can open appropriate Activity on launch and make list item position selected accordingly.  
* */
private static boolean isLaunch = true;

/**
*  Base layout node of this Activity.  
* */
private DrawerLayout mDrawerLayout;

/**
* Drawer listner class for drawer open, close etc.
*/
private ActionBarDrawerToggle actionBarDrawerToggle;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.navigation_drawer_base_layout);

frameLayout = (FrameLayout)findViewById(R.id.content_frame);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerList = (ListView) findViewById(R.id.left_drawer);

// set a custom shadow that overlays the main content when the drawer opens
//mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
     
// set up the drawer's list view with items and click listener
mDrawerList.setAdapter(new ArrayAdapter<String>(this, R.layout.drawer_list_item, listArray));
mDrawerList.setOnItemClickListener(new OnItemClickListener() {

@Override
public void onItemClick(AdapterView<?> parent, View view,
int position, long id) {

openActivity(position);
}
});

// enable ActionBar app icon to behave as action to toggle nav drawer
getActionBar().setDisplayHomeAsUpEnabled(true);
getActionBar().setHomeButtonEnabled(true);

// ActionBarDrawerToggle ties together the the proper interactions between the sliding drawer and the action bar app icon
actionBarDrawerToggle = new ActionBarDrawerToggle(
this, /* host Activity */
mDrawerLayout, /* DrawerLayout object */
R.drawable.ic_launcher,     /* nav drawer image to replace 'Up' caret */
R.string.open_drawer,       /* "open drawer" description for accessibility */
R.string.close_drawer)      /* "close drawer" description for accessibility */
{
@Override
public void onDrawerClosed(View drawerView) {
getActionBar().setTitle(listArray[position]);
                invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
super.onDrawerClosed(drawerView);
}

@Override
public void onDrawerOpened(View drawerView) {
getActionBar().setTitle(getString(R.string.app_name));
                invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
super.onDrawerOpened(drawerView);
}

@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
super.onDrawerSlide(drawerView, slideOffset);
}

@Override
public void onDrawerStateChanged(int newState) {
super.onDrawerStateChanged(newState);
}
};
mDrawerLayout.setDrawerListener(actionBarDrawerToggle);


/**
* As we are calling BaseActivity from manifest file and this base activity is intended just to add navigation drawer in our app.
* We have to open some activity with layout on launch. So we are checking if this BaseActivity is called first time then we are opening our first activity.
* */
if(isLaunch){
/**
 *Setting this flag false so that next time it will not open our first activity.
 *We have to use this flag because we are using this BaseActivity as parent activity to our other activity.
 *In this case this base activity will always be call when any child activity will launch.
 */
isLaunch = false;
openActivity(0);
}
}

/**
* @param position
*
* Launching activity when any list item is clicked.
*/
protected void openActivity(int position) {

/**
* We can set title & itemChecked here but as this BaseActivity is parent for other activity,
* So whenever any activity is going to launch this BaseActivity is also going to be called and
* it will reset this value because of initialization in onCreate method.
* So that we are setting this in child activity.  
*/
// mDrawerList.setItemChecked(position, true);
// setTitle(listArray[position]);
mDrawerLayout.closeDrawer(mDrawerList);
BaseActivity.position = position; //Setting currently selected position in this field so that it will be available in our child activities.

switch (position) {
case 0:
startActivity(new Intent(this, Item1Activity.class));
break;
case 1:
startActivity(new Intent(this, Item2Activity.class));
break;
case 2:
startActivity(new Intent(this, Item3Activity.class));
break;
case 3:
startActivity(new Intent(this, Item4Activity.class));
break;
case 4:
startActivity(new Intent(this, Item5Activity.class));
break;

default:
break;
}

Toast.makeText(this, "Selected Item Position::"+position, Toast.LENGTH_LONG).show();
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {

getMenuInflater().inflate(R.menu.main, menu);
return super.onCreateOptionsMenu(menu);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {

// The action bar home/up action should open or close the drawer.
// ActionBarDrawerToggle will take care of this.
if (actionBarDrawerToggle.onOptionsItemSelected(item)) {
            return true;
        }

switch (item.getItemId()) {
case R.id.action_settings:
return true;

default:
return super.onOptionsItemSelected(item);
}
}

/* Called whenever we call invalidateOptionsMenu() */
    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        // If the nav drawer is open, hide action items related to the content view
        boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
        menu.findItem(R.id.action_settings).setVisible(!drawerOpen);
        return super.onPrepareOptionsMenu(menu);
    }
 
    /* We can override onBackPressed method to toggle navigation drawer*/
@Override
public void onBackPressed() {
if(mDrawerLayout.isDrawerOpen(mDrawerList)){
mDrawerLayout.closeDrawer(mDrawerList);
}else {
mDrawerLayout.openDrawer(mDrawerList);
}
}
}

Item1Activity.java

package com.navigation.drawer.activity;

import android.os.Bundle;
import android.widget.ImageView;

/**
 * @author dipenp
 *
 */
public class Item1Activity extends BaseActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

              /**
*  We will not use setContentView in this activty 
*  Rather than we will use layout inflater to add view in FrameLayout of our base activity layout*/

/**
* Adding our layout to parent class frame layout.
*/
getLayoutInflater().inflate(R.layout.activity_main, frameLayout);

/**
* Setting title and itemChecked
*/
mDrawerList.setItemChecked(position, true);
setTitle(listArray[position]);

((ImageView)findViewById(R.id.image_view)).setBackgroundResource(R.drawable.image1);
}
}

Final view of our demo app:::



You can download demo code from below url:
https://drive.google.com/file/d/0B0mH97AUwQqhNUlxdmkwZ1JsNW8/edit?usp=sharing


------------------------------------------------------------------------------------------------------------
Attaching another demo example here as lots of visitors are getting confused how to add different layout on different activity and how to add icon on navigation list view. 
As well as added header on listview to make it little bit attractive.






You can download demo code from below url:



67 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Thank you for this helpful tutorial.I use it in my app.
    After selecting option from navigation drawer it adds corresponding activity into activity stack,and as per my app requiement i had to avoid it.Normally activity was being popped out by pressing back button.
    To avoid this i added noHistory=true in manifest and now it is working well,can you think of or suggest alternative way or above way is good?

    ReplyDelete
    Replies
    1. hi bro, i am facing same problem ans noHistory not work. plz help me.

      Delete
  3. Hi Hardik, Your solution seems fine....I will update you if find some other way to do the same...

    ReplyDelete
  4. I have problem for this , my AEID creater says direct running error ...help me ...truly

    ReplyDelete
  5. direct running permission is granted by superSU ...other project doing well but what happen to this .download file have same error

    ReplyDelete
  6. This comment has been removed by the author.

    ReplyDelete
  7. I have a splashscreen and a home_activity.
    In both don't want to have the menu bar.
    So, my splashcreen navigates with intent to home_activity and now, from home_activity i try to navigate with intent to BaseActivity as your example, in which BaseActivity is the launcher activity.
    But when i press the button in home_activity, before it opens the BaseActivity i get a NullPointerException.
    I get this error even if I changed the launcher activity in manifest to be BaseActivity, as you did.
    Can you help me after I post my code of BaseActivity here maybe ?

    ReplyDelete
    Replies
    1. Hi, If you are still facing same issue, please send me your code, I will check it.

      Delete
  8. How Can I Put Images With Naigationbar with Activity....

    ReplyDelete
    Replies
    1. Hi, If I am not wrong...you need image with listview of navigation drawer.....for that, you can have custom listview with custom adapter in your code.....

      Delete
  9. This comment has been removed by the author.

    ReplyDelete
  10. Thanx for such a gr8 tutorial , it works.

    ReplyDelete
  11. Hi , I have implemented Nav Drawer in my app. I use fragments to switch screens and it works just fine. But the problem is I want to add clickable buttons in my fragments (or activities, I might say). When clicked, the button should change screen to specific activity but I'm unable to add that code to fragment files. So what happens is : when I click on a button, the app crashes. Can you suggest a way to keep both ways of navigating within the app (i.e. using Nav Drawer & Buttons) ? Thanks in advance.

    ReplyDelete
    Replies
    1. Hey Nickforya did you solve your problem? I have the same problem with you. I'm a total newbie in Android.

      Delete
  12. Hi. It's not navigating to any other activities. (from item 1 to item 2 or 3 or 4 or 5).any help would be appreciated.

    thanks.

    ReplyDelete
  13. Thanks you for that!
    Here, the drawer is recreated and reconfigured in each activities.
    Is there a way to have a clean implementation, only 1 instance of the drawer shared between all activities ?

    ReplyDelete
  14. Thank you for very nice tutuorial.
    But how to use different layouts for different activities, not just setBackgroundResource() ?
    I need different layouts with different buttons etc. on different activities

    ReplyDelete
    Replies
    1. You can create your own layout and add it on parent class frame layout like this.
      getLayoutInflater().inflate(R.layout.activity_main, frameLayout);

      You can find this line on every activity of our demo.

      Delete
    2. could you please elaborate a bit? I mean how do i add a separate layout for each of the other activities???

      Delete
    3. On every activity you have this line :

      getLayoutInflater().inflate(R.layout.activity_main, frameLayout);

      Add your own layout on first parameter... that is "R.layout.activity_main"....add your own layout id in this place.

      Delete
  15. This comment has been removed by the author.

    ReplyDelete
  16. Thanks mate.. All other tutorials show nav drawer with fragments but I was looking for this use case :)
    One question, Instead of listview if I use navigationView provided in design support library for nav drawer menu, would your solution still work or do you see any problem?

    ReplyDelete
  17. hey.. i wanted to know if i could have separate view for each of the 'item3activity' besides its main layout ...

    ReplyDelete
    Replies
    1. On every activity you have this line :

      getLayoutInflater().inflate(R.layout.activity_main, frameLayout);

      Add your own layout on first parameter... that is "R.layout.activity_main"....add your own layout id in this place.

      Delete
  18. Thanks Dipen.. useful tutorial. but i want to drawer should cover status bar too. is it possile in thhis with fragment

    ReplyDelete
  19. hi i tried ur code but wen i run the app and select 2 or 3 option in the menu the aplication crash

    FATAL EXCEPTION: main
    Process: com.navigation.drawer.activity, PID: 11914
    java.lang.OutOfMemoryError


    the app spend alot of memory i tink

    ReplyDelete
    Replies
    1. Hi, I have used some high resolution images to render on activity layout.....replace those images with low resolution (less size image) and it will work fine.

      Delete
  20. Hii thanks for this tutorial,
    I am trying to use image icons along with the text in the navigation drawer listview, but then the application shows errors at runtime, could you help me with that.
    Thank You

    ReplyDelete
    Replies
    1. You can use "custom list view" to render on navigation drawer list view.
      Where you can render any kind of layout you want.

      Delete
  21. Excelente, el codigo funciona de 10... me sirve mucho para una aplicación que estoy desarrollando... excelente aporte

    ReplyDelete
  22. This comment has been removed by the author.

    ReplyDelete
  23. Hi this a good one. Im still learning about android programming, how do i have separate an activity, for example, a register activity before the whole thinng?

    ReplyDelete
  24. Hello..I'm newbie in Android and I've find this tutorial really easy and I've learn quickly about the navDrawer. But I'm facing some issue regarding the NULLPOINTEREXCEPTION at getActionBar.setDisplayShowHomeEnabled(true).. please help I'm trying to sor this issue myself but no progress..

    ReplyDelete
  25. Try to increase the Android api version of your project...check if it works

    ReplyDelete
    Replies
    1. I have the same issue but increase the android api version of my project don't work. i have change the theme so it's work but it's not very beautifull

      Delete
    2. hey,i too got the same problem wat should i do??i tried increaseing the api version bt it did nt work

      Delete
  26. this error shows on kitkat
    Caused by: java.lang.reflect.InvocationTargetException
    Caused by: android.view.InflateException: Binary XML file line #2: Error inflating class android.support.design.widget.NavigationView

    ReplyDelete
  27. Thank you, it work well!

    But about BackPress, if I remove onBackPressed() of BaseActivity , it seem more logical ? Because in an actvity, when Hard-Back-Press, it should be back to previous activity rather than show NavigationBar ?

    ReplyDelete
  28. Thank you, it work well!

    But about BackPress, if I remove onBackPressed() of BaseActivity , it seem more logical ? Because in an actvity, when Hard-Back-Press, it should be back to previous activity rather than show NavigationBar ?

    ReplyDelete
  29. Patel mara project ma 1 locho thayo che, mare navigation drawer toolbar na niche joiche pan ae thatu nathi. toolbar ouverlap thai che maro. if possible help me if you want i can share my code and my files

    ReplyDelete
  30. Hi I am a student and new to Android developing.Y our tutorial is exactly what I've been looking for, but I am facing one serious problem.
    When I extend one of my activities with BaseActivity, it also replaces the layout of the activity instead of just adding the navigation drawer. How do i fix that?

    Thank you very much in advance
    best wishes

    ReplyDelete
    Replies
    1. This comment has been removed by the author.

      Delete
    2. It shows the image1.jpg instead of the layout of my child activity

      Delete
    3. Nvm, I think i fixed it by changing the layout in the itemActitivites getLayoutInflater().inflate(R.layout.yourlayouhere, frameLayout);

      Delete
  31. This comment has been removed by the author.

    ReplyDelete
  32. getActionBar().setDisplayHomeAsUpEnabled(true);
    getActionBar().setHomeButtonEnabled(true);


    nullpointerexception

    ReplyDelete
    Replies
    1. Increase your App API version or try to add support library in your project.

      Delete
  33. your tutorial is amazing....sir.....

    ReplyDelete
  34. This comment has been removed by the author.

    ReplyDelete
  35. Thank you for your tutorial. I'm making an app that uses Activities with a DrawerLayout. When you click an item on the drawer menu, it's supposed to show the next screen while closing the drawer. However, when you click on an item, the Activity launches immediately and it cuts off the closing of the drawer. Is there any way to remedy this?

    ReplyDelete
  36. Thanks for the tutorial, it was a good starting point, but do you know of any RECENT examples with current Android SDK codebases ? A lot of things in this code are deprecated. If you set up a new DrawerLayout project in Android Studio 2.2, the sample app has a lot less code, and I've got it working with multiple activities, the only problem is that once you go past the first activity, the navigationview is put onto a second line (like a second actionbar)

    ReplyDelete
  37. Thanks alot.Worked Perfectly for me.

    ReplyDelete
  38. Can you send me the complete code in android studio I am not able to use the following github code

    ReplyDelete
  39. Can you send me the complete code in android studio I am not able to use the following github code to this email id tarigonda9sekhar123@gmail.com

    ReplyDelete
  40. Here is a complete working example that SO did not want:

    https://github.com/jj30/MyApp

    ENJOY

    ReplyDelete
  41. Hi Dipen , I have a query that when i write the line in the my item_activity1 class that is

    getLayoutInflater().inflate(R.layout.tabs, frameLayout);

    mDrawerList.setItemChecked(position, true);
    setTitle(listArray[position]);

    it shows error bcoz it that class in my project aleready extended from another class
    that is Tabactivity like as follows .

    public class ItemActivity1 extends Tabactivity{

    then what should i have to do...?

    ReplyDelete
  42. I can nor understand this.please, change navigation icon....and this apps can not exit

    ReplyDelete
  43. I was looking for Quality Personal Statement Writing Help before I landed on this page. Although I did not find the exact services that I was looking for, I have found important information that has enlighten me. Thanks for sharing this information with us, we are looking forward to reading more new posts.

    ReplyDelete
  44. I have been developing a lot of interest in android development and thus I find this blog to be very useful to me. Navigations are found in all the user interfaces and thus learning about them is very crucial. Android navigation should be set into an extent that the user elements will be visible. Where to get Essay Topic Ideas

    ReplyDelete
  45. how i tried your project but i get error on during runtime. it just crashes the moment i run it. can you help me? i simply copied everything so there is no way there is an error in the codes.

    ReplyDelete
  46. Stop putting message that is irrelevant to my blog...I or my viewer dont want your quickbook or slowbook.

    STOP SPAMMING

    ReplyDelete
  47. QuickBooks Payroll has emerged among the best accounting software which has had changed the meaning of payroll. Quickbooks Payroll Support contact number will be the team that provide you QuickBooks Payroll Support Number

    ReplyDelete
    Replies
    1. Again your message on my blog.
      You are shameless

      Delete