Create A Navigation Drawer in Android

OVERVIEW

Most modern apps have a sliding Navigation Drawer as the main navigation element. This seems to be the modern version replacement of the sliding TabHost which was the main navigation element a few years back. Note that this UI component is not natively available for Android versions older than 4.x (Icecream Sandwich). The example below is meant for apps targeting SDK 19 and later i.e. KitKat and later. Perhaps it might work for slightly older versions, but I am not sure.

METHODOLOGY

We create the NavigationDrawer as a Fragment which can be called from multiple Activities. So if your app has 5 Activity screens, then each of them will call this Fragment in code and also provide for it in their layouts. The example has a single Activity only called MainActivity

Layouts

The layout for MainActivity called activity_main.xml will have the root layout as

android.support.v4.widget.DrawerLayout

instead of the standard LinearLayout or RelativeLayout . Within  the root layout there is a FrameLayout. Below the FrameLayout there be a single layout (LinearLayout in this case) which will hold the content for the Activity. Below this single layout, the fragment for the NavigationDrawer will be placed.

The NavigationDrawer itself consists of two layouts drawer_drawer.xml and drawer_header.xml .

As the names suggest, the main drawer component UI is set in drawer_drawer and the header UI is fixed in drawer_header.

Since we are going to put a menu with submenus within the drawer, we have two additional layout files – one to fix the UI for the top level menu groups  list_group.xml and the second for the submenu items – list_item.xml

 

It is not necessary that the NavigationDrawer should only have menus. It can contain anything ,but most of the times a menu is the standard usage pattern for it.

Drawables

We have three drawables used here:

ic_drawer.png – the icon for drawer

actionbar_background.xml – background UI for the drawer when it is open

drawer_shadow_9.png  – a 9 patch image for dropping a shadow when the drawer is visible

 

Values

dimens.xml – standard dimension values for the navigation drawer

styles.xml – style settings for the app

strings.xml – various string values used in the drawer

 

Assets

We will be putting icons for each menu item group in the Drawer, so we will use font awesome to put icons within our menu text. You can , use images or icons directly, but its easier to use font-awesome if you are just looking for standard icon notation.

Within our app folder, we will create assets folder and within that the fonts folder. Within the fonts folder will put the ttf file for font-awesome.

Classes

MainActivity.class – the main activity which will call the drawer.

NavigationDrawerFragment.class – the Class to handle the drawer fragment

ExpandableListDataPump.class – this provides the menu content

ExpandableListAdapter.class – the expandable list handler which will control the menu

FontManager.class – Utility class to access Font-awesome

 

SOURCE LISTINGS

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="navdrawer.test.com.navigationdrawertest">

    <uses-sdk
        android:minSdkVersion="19"
        android:targetSdkVersion="23" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

actionbar_background.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <gradient
        android:startColor="#444444"
        android:endColor="#aaaaaa"
        android:angle="0" />
</shape>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.widget.DrawerLayout  xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/main_layout"
    android:background="#ffffff"
    tools:context="navdrawer.test.com.navigationdrawertest.MainActivity">

    <!-- As the main content view, the view below consumes the entire
      space available using match_parent in both dimensions. -->
    <FrameLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:paddingTop="20dp"
        android:paddingBottom="20dp"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"

        >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Content comes here"
        />

    </LinearLayout>

    <!-- The drawer is given a fixed width in dp and extends the full height of
       the container. -->
    <fragment android:id="@+id/navigation_drawer"
        android:layout_width="@dimen/navigation_drawer_width"
        android:layout_height="match_parent"
        android:layout_gravity="start"

        android:name="navdrawer.test.com.navigationdrawertest.NavigationDrawerFragment"
        tools:layout="@layout/drawer_drawer" />


</android.support.v4.widget.DrawerLayout>

drawer_drawer.xml

<ExpandableListView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/list_slidermenu"
    android:layout_width="300dp"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:background="@drawable/actionbar_background"
    android:choiceMode="singleChoice"
    android:divider="#ffffff"
    android:dividerHeight="0.2dp"
    android:groupIndicator="@null"
    android:alpha="255"
    android:indicatorLeft="?android:attr/expandableListPreferredItemIndicatorLeft"
    >
</ExpandableListView>

drawer_header.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" >
    <RelativeLayout
        android:id="@+id/RelativeLayout1"
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:background="#000000" >
        <TextView
            android:id="@+id/textDrawerHeading"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_alignParentTop="true"
            android:layout_margin="5dp"
            android:textAlignment="center"
            android:gravity="center_vertical"
            android:text="Header Text Comes Here"
            android:textAppearance="?android:attr/textAppearanceMedium"
            android:textColor="#ffffff"
            android:textStyle="bold" />

    </RelativeLayout>
</FrameLayout>

list_group.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <TextView
        android:id="@+id/listTitleIcon"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:paddingLeft="5dp"
        android:textColor="#ffffff"
        android:paddingTop="12dp"
        android:paddingBottom="12dp"
        android:layout_weight="0.60"
        android:textSize="18dp"/>
    <TextView
        android:id="@+id/listTitle"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:paddingLeft="5dp"
        android:textColor="#ffffff"
        android:paddingTop="12dp"
        android:paddingBottom="12dp"
        android:layout_weight="0.20"/>
    <TextView
        android:id="@+id/listTitleArrow"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:paddingRight="5dp"
        android:textColor="#ffffff"
        android:paddingTop="12dp"
        android:paddingBottom="12dp"
        android:layout_weight="0.60"
        android:textAlignment="viewEnd"
        android:text="X"
        android:textSize="18dp"/>

</LinearLayout>

list_item.xml

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <TextView
        android:id="@+id/expandedListItem"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:textColor="#ffffff"
        android:paddingLeft="60dp"
        android:paddingTop="10dp"
        android:paddingBottom="10dp" />
</LinearLayout>

dimens.xml

<resources>
    <!-- Default screen margins, per the Android Design guidelines. -->
    <dimen name="activity_horizontal_margin">16dp</dimen>
    <dimen name="activity_vertical_margin">16dp</dimen>

    <!-- Per the design guidelines, navigation drawers should be between 240dp and 320dp:
       https://developer.android.com/design/patterns/navigation-drawer.html -->
    <dimen name="navigation_drawer_width">240dp</dimen>

</resources>

strings.xml

<resources>
    <string name="app_name">NavigationDrawerTest</string>
    <string name="action_settings">Settings</string>
    <string name="drawer_open"></string>
    <string name="drawer_close"></string>

    <string name="fa_glass">&#xf000;</string>
    <string name="fa_music">&#xf001;</string>
    <string name="fa_search">&#xf002;</string>
    <string name="fa_envelope_o">&#xf003;</string>
    <string name="fa_heart">&#xf004;</string>
    <string name="fa_star">&#xf005;</string>
    <string name="fa_star_o">&#xf006;</string>
    <string name="fa_user">&#xf007;</string>
    <string name="fa_film">&#xf008;</string>
    <string name="fa_chevron_right">&#xf054;</string>
    <string name="fa_chevron_down">&#xf078;</string>
</resources>

styles.xml

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
    </style>



</resources>

ExpandableListAdapter.java

package navdrawer.test.com.navigationdrawertest;

import java.util.HashMap;
import java.util.List;
import android.content.Context;
import android.graphics.Typeface;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.TextView;
import android.widget.ExpandableListView.OnGroupClickListener;


public class ExpandableListAdapter extends BaseExpandableListAdapter {

    private Context context;
    private List<String> expandableListTitle;
    private HashMap<String, List<String>> expandableListDetail;

    public static int ITEM1 = 0;
    public static int ITEM2 = 1;
    public static int ITEM3 = 2;
    public static int ITEM4 = 3;


    public static int SUBITEM1_1 = 0;
    public static int SUBITEM1_2 = 1;
    public static int SUBITEM1_3 = 2;
    public static int SUBITEM1_4 = 3;


    public static int SUBITEM2_1 = 0;
    public static int SUBITEM2_2 = 1;
    public static int SUBITEM2_3 = 2;
    public static int SUBITEM2_4 = 3;
   



    public ExpandableListAdapter(Context context, List<String> expandableListTitle,
                                 HashMap<String, List<String>> expandableListDetail) {
        this.context = context;
        this.expandableListTitle = expandableListTitle;
        this.expandableListDetail = expandableListDetail;


    }

    @Override
    public Object getChild(int listPosition, int expandedListPosition) {
        return this.expandableListDetail.get(this.expandableListTitle.get(listPosition))
                .get(expandedListPosition);
    }

    @Override
    public long getChildId(int listPosition, int expandedListPosition) {
        return expandedListPosition;
    }

    @Override
    public View getChildView(int listPosition, final int expandedListPosition,
                             boolean isLastChild, View convertView, ViewGroup parent) {
        final String expandedListText = (String) getChild(listPosition, expandedListPosition);
        if (convertView == null) {
            LayoutInflater layoutInflater = (LayoutInflater) this.context
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = layoutInflater.inflate(R.layout.list_item, null);
        }
        TextView expandedListTextView = (TextView) convertView
                .findViewById(R.id.expandedListItem);
        expandedListTextView.setText(expandedListText);
        return convertView;
    }

    @Override
    public int getChildrenCount(int listPosition) {
        return this.expandableListDetail.get(this.expandableListTitle.get(listPosition))
                .size();
    }

    @Override
    public Object getGroup(int listPosition) {
        return this.expandableListTitle.get(listPosition);
    }

    @Override
    public int getGroupCount() {
        return this.expandableListTitle.size();
    }

    @Override
    public long getGroupId(int listPosition) {
        return listPosition;
    }

    @Override
    public View getGroupView(int listPosition, boolean isExpanded,
                             View convertView, ViewGroup parent) {
        String listTitle = (String) getGroup(listPosition);
        if (convertView == null) {
            LayoutInflater layoutInflater = (LayoutInflater) this.context.
                    getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = layoutInflater.inflate(R.layout.list_group, null);
        }
        TextView listTitleTextView = (TextView) convertView
                .findViewById(R.id.listTitle);
        listTitleTextView.setTypeface(null, Typeface.NORMAL);
        listTitleTextView.setText(listTitle);


        TextView listTitleTextArrowView = (TextView) convertView
                .findViewById(R.id.listTitleArrow);
        listTitleTextArrowView.setTypeface(null, Typeface.NORMAL);
        listTitleTextArrowView.setTypeface(FontManager.getTypeface(context, FontManager.FONTAWESOME));

        // set icons for menu items
        TextView listTitleTextIconView = (TextView) convertView
                .findViewById(R.id.listTitleIcon);
        listTitleTextIconView.setTypeface(null, Typeface.NORMAL);
        listTitleTextIconView.setTypeface(FontManager.getTypeface(context, FontManager.FONTAWESOME));
        if (listPosition == ITEM1)
            listTitleTextIconView.setText(context.getResources().getString(R.string.fa_glass));
        else if (listPosition == ITEM2)
            listTitleTextIconView.setText(context.getResources().getString(R.string.fa_music));
        else if (listPosition == ITEM3)
            listTitleTextIconView.setText(context.getResources().getString(R.string.fa_search));
        else if (listPosition == ITEM4)
            listTitleTextIconView.setText(context.getResources().getString(R.string.fa_envelope_o));

        // set arrow icons for relevant items
        if (listPosition == ITEM1 || listPosition == ITEM2) {
            if (!isExpanded)
                listTitleTextArrowView.setText(context.getResources().getString(R.string.fa_chevron_right));
            else
                listTitleTextArrowView.setText(context.getResources().getString(R.string.fa_chevron_down));
        } else {
            listTitleTextArrowView.setText("");

        }
        return convertView;
    }

    @Override
    public boolean hasStableIds() {
        return false;
    }

    @Override
    public boolean isChildSelectable(int listPosition, int expandedListPosition) {
        return true;
    }

}

ExpandableListDataPump.java

package navdrawer.test.com.navigationdrawertest;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;

public class ExpandableListDataPump {
    public static HashMap<String, List<String>> getData() {
        LinkedHashMap<String, List<String>> expandableListDetail = new LinkedHashMap<String, List<String>>();

        List<String> menu3 = new ArrayList<String>();
        List<String> menu4 = new ArrayList<String>();

        List<String> list1 = new ArrayList<String>();
        list1.add("Submenu 1");
        list1.add("Submenu 2");
        list1.add("Submenu 3");
        list1.add("Submenu 4");


        List<String> list2 = new ArrayList<String>();
        list2.add("Submenu 1");
        list2.add("Submenu 2");
        list2.add("Submenu 3");
        list2.add("Submenu 4");


        expandableListDetail.put("Menu 1", list1);
        expandableListDetail.put("Menu 2", list2);
        expandableListDetail.put("Menu 3", menu3);
        expandableListDetail.put("Menu 4", menu4);


        return expandableListDetail;
    }
}

FontManager.java

package navdrawer.test.com.navigationdrawertest;



import android.content.Context;
import android.graphics.Typeface;
import android.view.View;

/**
 * Created by amit on 26/3/16.
 */
public class FontManager {

    public static final String ROOT = "fonts/",
            FONTAWESOME = ROOT + "fontawesome-webfont.ttf";

    public static Typeface getTypeface(Context context, String font) {
        return Typeface.createFromAsset(context.getAssets(), font);
    }
}

MainActivity.java

package navdrawer.test.com.navigationdrawertest;

import android.content.Intent;
import android.support.v7.app.ActionBarActivity;
import android.app.Activity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;


public class MainActivity extends ActionBarActivity
        implements NavigationDrawerFragment.NavigationDrawerCallbacks {

    private NavigationDrawerFragment mNavigationDrawerFragment;
    private CharSequence mTitle;
    private DrawerLayout mDrawerLayout;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        getSupportActionBar().setTitle("Home");


        // Set up the drawer.

        mNavigationDrawerFragment = (NavigationDrawerFragment)
                getSupportFragmentManager().findFragmentById(R.id.navigation_drawer);
        mTitle = getTitle();
        mNavigationDrawerFragment.setUp(
                R.id.navigation_drawer,
                (DrawerLayout) findViewById(R.id.main_layout));

        mDrawerLayout = (DrawerLayout) findViewById(R.id.main_layout);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, 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();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void onNavigationDrawerItemSelected(int position) {
        // update the main content by replacing fragments

    }



}

NavigationDrawerFragment.java

package navdrawer.test.com.navigationdrawertest;

import android.content.Intent;
import android.support.v7.app.ActionBarActivity;
import android.app.Activity;
import android.support.v7.app.ActionBar;
import android.support.v4.app.Fragment;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.content.res.Configuration;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ExpandableListView;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import android.widget.ExpandableListView.OnGroupCollapseListener;
import android.widget.ExpandableListView.OnGroupExpandListener;

/**
 * Fragment used for managing interactions for and presentation of a navigation drawer.
 * See the <a href="https://developer.android.com/design/patterns/navigation-drawer.html#Interaction">
 * design guidelines</a> for a complete explanation of the behaviors implemented here.
 */
public class NavigationDrawerFragment extends Fragment {

    private static final String STATE_SELECTED_POSITION = "selected_navigation_drawer_position";

    private NavigationDrawerCallbacks mCallbacks;

    private ActionBarDrawerToggle mDrawerToggle;

    private DrawerLayout mDrawerLayout;
    private ExpandableListView mDrawerListView;
    private View mFragmentContainerView;

    private int mCurrentSelectedPosition = 0;


    ArrayList<String> groupItem = new ArrayList<String>();
    ArrayList<Object> childItem = new ArrayList<Object>();

    List<String> expandableListTitle;
    HashMap<String, List<String>> expandableListDetail;

    public NavigationDrawerFragment() {
    }

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

    }

    @Override
    public void onActivityCreated (Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        // Indicate that this fragment would like to influence the set of actions in the action bar.
        setHasOptionsMenu(true);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        mDrawerListView = (ExpandableListView) inflater.inflate(
                R.layout.drawer_drawer, container, false);
        mDrawerListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                selectItem(position);
            }
        });

        expandableListDetail = ExpandableListDataPump.getData();
        expandableListTitle = new ArrayList<String>(expandableListDetail.keySet());


        mDrawerListView.setAdapter(new ExpandableListAdapter(getActivity(), expandableListTitle, expandableListDetail));

        mDrawerListView.setOnGroupExpandListener(new OnGroupExpandListener() {

            @Override
            public void onGroupExpand(int groupPosition) {

            }
        });


        mDrawerListView.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() {
            public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) {
                boolean retVal = true;

                if (groupPosition == ExpandableListAdapter.ITEM1) {
                    retVal = false;
                } else if (groupPosition == ExpandableListAdapter.ITEM2) {
                    retVal = false;
                } else if (groupPosition == ExpandableListAdapter.ITEM3) {

                    // call some activity here
                } else if (groupPosition == ExpandableListAdapter.ITEM4) {
                    // call some activity here

                }
                return retVal;
            }
        });

        mDrawerListView.setOnChildClickListener(new ExpandableListView.OnChildClickListener() {

            @Override
            public boolean onChildClick(ExpandableListView parent, View v,
                                        int groupPosition, int childPosition, long id) {

                if (groupPosition == ExpandableListAdapter.ITEM1) {
                    if (childPosition == ExpandableListAdapter.SUBITEM1_1) {

                       // call activity here

                    }
                    else if (childPosition == ExpandableListAdapter.SUBITEM1_2) {

                       // call activity here

                    }
                    else if (childPosition == ExpandableListAdapter.SUBITEM1_3) {

                        // call activity here

                    }
                    else if (childPosition == ExpandableListAdapter.SUBITEM1_4) {

                        // call activity here

                    }


                } else if (groupPosition == ExpandableListAdapter.ITEM2) {

                    if (childPosition == ExpandableListAdapter.SUBITEM2_1) {

                        // call activity here

                    }
                    else if (childPosition == ExpandableListAdapter.SUBITEM2_2) {

                        // call activity here

                    }
                    else if (childPosition == ExpandableListAdapter.SUBITEM2_3) {

                        // call activity here

                    }
                    else if (childPosition == ExpandableListAdapter.SUBITEM2_4) {

                        // call activity here

                    }


                }
                return true;
            }
        });

        mDrawerListView.setItemChecked(mCurrentSelectedPosition, true);

        View header= inflater.inflate(R.layout.drawer_header, null);
        mDrawerListView.addHeaderView(header);


        return mDrawerListView;
    }



    public boolean isDrawerOpen() {
        return mDrawerLayout != null && mDrawerLayout.isDrawerOpen(mFragmentContainerView);
    }

    /**
     * Users of this fragment must call this method to set up the navigation drawer interactions.
     *
     * @param fragmentId   The android:id of this fragment in its activity's layout.
     * @param drawerLayout The DrawerLayout containing this fragment's UI.
     */
    public void setUp(int fragmentId, DrawerLayout drawerLayout) {
        mFragmentContainerView = getActivity().findViewById(fragmentId);
        mDrawerLayout = drawerLayout;

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

        ActionBar actionBar = getActionBar();
       actionBar.setDisplayHomeAsUpEnabled(true);
        actionBar.setHomeButtonEnabled(true);

        // ActionBarDrawerToggle ties together the the proper interactions
        // between the navigation drawer and the action bar app icon.
        mDrawerToggle = new ActionBarDrawerToggle(
                getActivity(),                    /* host Activity */
                mDrawerLayout,                    /* DrawerLayout object */
                R.string.drawer_open,  /* "open drawer" description for accessibility */
                R.string.drawer_close  /* "close drawer" description for accessibility */
        ) {
            @Override
            public void onDrawerClosed(View drawerView) {
                super.onDrawerClosed(drawerView);
                getActionBar().setIcon(R.drawable.ic_drawer);

                if (!isAdded()) {
                    return;
                }

                getActivity().supportInvalidateOptionsMenu(); // calls onPrepareOptionsMenu()
            }

            @Override
            public void onDrawerOpened(View drawerView) {
                super.onDrawerOpened(drawerView);


                if (!isAdded()) {
                    return;
                }



                getActivity().supportInvalidateOptionsMenu(); // calls onPrepareOptionsMenu()
            }
        };


        // Defer code dependent on restoration of previous instance state.
        mDrawerLayout.post(new Runnable() {
            @Override
            public void run() {
                mDrawerToggle.syncState();
            }
        });

        mDrawerLayout.setDrawerListener(mDrawerToggle);
    }

    private void selectItem(int position) {
        mCurrentSelectedPosition = position;
        if (mDrawerListView != null) {
            mDrawerListView.setItemChecked(position, true);
        }
        if (mDrawerLayout != null) {
            mDrawerLayout.closeDrawer(mFragmentContainerView);
        }
        if (mCallbacks != null) {
            mCallbacks.onNavigationDrawerItemSelected(position);
        }
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            mCallbacks = (NavigationDrawerCallbacks) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException("Activity must implement NavigationDrawerCallbacks.");
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        mCallbacks = null;
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt(STATE_SELECTED_POSITION, mCurrentSelectedPosition);
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        // Forward the new configuration the drawer toggle component.
        mDrawerToggle.onConfigurationChanged(newConfig);
    }

    @Override
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        // If the drawer is open, show the global app actions in the action bar. See also
        // showGlobalContextActionBar, which controls the top-left area of the action bar.
        if (mDrawerLayout != null && isDrawerOpen()) {
            inflater.inflate(R.menu.menu_main, menu);
            showGlobalContextActionBar();
        }
        super.onCreateOptionsMenu(menu, inflater);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (mDrawerToggle.onOptionsItemSelected(item)) {
            return true;
        }


        return super.onOptionsItemSelected(item);
    }

    /**
     * Per the navigation drawer design guidelines, updates the action bar to show the global app
     * 'context', rather than just what's in the current screen.
     */
    private void showGlobalContextActionBar() {
        ActionBar actionBar = getActionBar();
        actionBar.setDisplayShowTitleEnabled(true);
        actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);

    }

    private ActionBar getActionBar() {
        return ((ActionBarActivity) getActivity()).getSupportActionBar();
    }

    /**
     * Callbacks interface that all activities using this fragment must implement.
     */
    public static interface NavigationDrawerCallbacks {
        /**
         * Called when an item in the navigation drawer is selected.
         */
        void onNavigationDrawerItemSelected(int position);
    }
}

SCREENSHOTS

Here is how the activity screen looks when the drawer is not open.

Screenshot_2016-04-21-16-22-03

 

 

 

 

 

 

 

 

 

 

 

 

 

This is how it looks when the drawer opens on tapping the app icon.

Screenshot_2016-04-21-16-22-11

 

 

 

 

 

 

 

 

 

 

 

 

 

The hamburger icon animates to turn into a left arrow. The reverse animation happens when the drawer is closed. If you dont see the icon changing, then make sure that in NavigationDrawerFragment.java  you are importing

import android.support.v7.app.ActionBarDrawerToggle;

instead of

import android.support.v4.app.ActionBarDrawerToggle;

 

The complete source code is downloadable from this link.

 

14 Comments

  1. @Abdi @Dipawali. As far as I know the navigation drawer is part of the official SDK only from version 19 onwards. If you are making an older version app then you can try using the Support library which has the navigation drawer functionality but the code will be different for that and all features might not work. Another alternative is to use a third party sliding menu which can run on older versions.

  2. hi thank you for the good tutorial,
    i want to open each fragment when user click onSetOnclickListener not as activity as a fragment
    how do that please help

  3. thank you so much this really helpfully.
    i have question if you can to help ,
    can you give me step to make the navigation drawer above Actionbar (toolbar) ?

  4. i checked it and work fine ty ,
    sorry last question , any step for fragment this items and subitems , i need step work with ur codes . i am sorry for bothering you , i still learn and i love to test alot of project to learn more

    • and can you tell me how to put this code , with ur code ! i tried many way but all time i got error
      i need to use this code to collapse group

      http://stackoverflow.com/a/32190162/2428653

      int lastExpandedGroupPosition = 0;
      [code]
      @Override
      public void onGroupExpanded(int groupPosition){
      //collapse the old expanded group, if not the same
      //as new group to expand
      if(groupPosition != lastExpandedGroupPosition){
      listView.collapseGroup(lastExpandedGroupPosition);
      }

      super.onGroupExpanded(groupPosition);
      lastExpandedGroupPosition = groupPosition;
      }

  5. @muller. It is not really much use to put each item in a fragment because a fragment represents a complete Activity so it is not meant to just be a simple UI. If you want to have complex displays for each item, then its better to create an xml layout in a separate file and then inflate it for the particular list item at runtime.

    What is the error you are getting when using onGroupExpanded

  6. 🙁
    as i told you i just start to learn it ,
    if you can help me just for some code
    when i press on Menu 3 Open xml file
    when i press on Submenu 1 Open xml file ,

    i search on google and find meany way, but every time i try to add it, i got error , and some time work , but when i press nothing happens, really i am so sorry if i am bothering you 🙁

  7. Hello, I have implemented the nav drawer in my app. I have a question, what will be the position of the child, when the second group is expanded. Where you have overrided – onNavigationDrawerItemSelected, and typed call fragments here. What will be the position of the child to call the fragment. Thank you!

Leave a Reply

Your email address will not be published.


*