Please enable JavaScript to view the comments powered by Disqus.

Android Sliding Menu using Navigation Drawer

A - Introduction Android Sliding Menu

Nowadays, a lot of Android applications use Sliding Menu to navigate between app’s modules/ screens. The Sliding Menu is hidden in the normal state and can be shown by swiping horizontally gesture or tapping on the app icon on the Action Bar.

Android Sliding Menu

Previously, if you want to create a Sliding Menu like this, the only way is using a third party library.

But now, Google support it with a newer concept called Navigation Drawer.

According to Google:

The navigation drawer is a panel that transitions in from the left edge of the screen and displays the app’s main navigation options.

In this post, we will learn how to create a Android Sliding Menu using Navigation Drawer.

B - Demo Application

1. Prepare resources

First of all, you need to download some images for the Sliding Menu and add them to the drawable folder:

  • Sliding menu icon: ic_drawer
  • Home icon: home
  • Settings icon: settings
  • Notifications icon: notifications
  • About icon: about

Open string.xml file, add some string variables for Sliding Menu items and icons name:

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

    <string name="app_name">Demo Sliding Menu</string>
    <string name="action_settings">Settings</string>
    <string name="hello_world">Hello world!</string>

    <!-- Sliding Menu items -->
    <string-array name="nav_drawer_items">
        <item >Home</item>
        <item >Notifications</item>
        <item >Settings</item>
        <item >About</item>
    </string-array>

    <!-- Sliding Menu item icons -->
    <array name="nav_drawer_icons">
        <item>@drawable/home</item>
        <item>@drawable/notifications</item>
        <item>@drawable/settings</item>
        <item>@drawable/about</item>
    </array>

</resources>

 

2. Edit main layout

Open activity_main.xml file and type the following code:

<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 to display Fragments -->
    <FrameLayout
        android:id="@+id/fragment_detail"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <!-- Listview to display Sliding Menu -->
    <ListView
        android:id="@+id/lv_sliding_menu"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:choiceMode="singleChoice"
        android:divider="#000"
        android:dividerHeight="1dp"/>
        
</android.support.v4.widget.DrawerLayout>

 

The FrameLayout will hold the appropriate Fragment (default is Home fragment).

The ListView will role the Sliding Menu.

3. Create Adapter for Sliding Menu ListView

As I mentioned in the Custom ListView post, every Custom ListView need an Adapter. But before coding for the Adapter, We need to create some layouts for the Sliding Menu ListView.

Create a layout file under the res –> layouts folder and name it lv_item_sliding_menu.xml. This layout has a ImageView and TextView to display Sliding Menu item.

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:paddingLeft="10dp"
    android:paddingRight="10dp"
    android:paddingTop="5dp" >

    <ImageView
        android:id="@+id/img_sliding_menu_item"
        android:layout_width="32dp"
        android:layout_height="32dp"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:src="@drawable/home" />

    <TextView
        android:id="@+id/tv_sliding_menu_item"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/img_sliding_menu_item"
        android:layout_toRightOf="@+id/img_sliding_menu_item"
        android:text="Home"
        android:layout_marginLeft="10dp"
        android:textAppearance="?android:attr/textAppearanceMedium" />

</RelativeLayout>

 

To bind items to a ListView. We need an entity to describe that item.

Create SlidingMenuItem class with following properties:

public class SlidingMenuItem {
    String title;
    int icon;

    public SlidingMenuItem(String title, int icon) {
        this.title = title;
        this.icon = icon;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public int getIcon() {
        return icon;
    }

    public void setIcon(int icon) {
        this.icon = icon;
    }

}

 

Now, everything is ready to code the adapter.

Create SlidingMenuAdapter class that extends BaseAdapter:

public class SlidingMenuAdapter extends BaseAdapter {

    private Context context;
    private ArrayList<SlidingMenuItem> items;

    public SlidingMenuAdapter(Context context, ArrayList<SlidingMenuItem> items) {
        this.context = context;
        this.items = items;
    }

    @Override
    public int getCount() {
        return items.size();
    }

    @Override
    public Object getItem(int index) {
        return items.get(index);
    }

    @Override
    public long getItemId(int index) {
        return index;
    }

    @Override
    public View getView(int index, View view, ViewGroup arg2) {
        if (view == null) {
            LayoutInflater mInflater = (LayoutInflater)
            context.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
            view = mInflater.inflate(R.layout.lv_item_sliding_menu, null);
        }

        ImageView imgIcon = (ImageView) view.findViewById(R.id.img_sliding_menu_item);
        TextView txtTitle = (TextView) view.findViewById(R.id.tv_sliding_menu_item);

        SlidingMenuItem item = items.get(index);

        imgIcon.setImageResource(item.getIcon());
        txtTitle.setText(item.getTitle());

        return view;
    }

}

 

Until now, we did every thing needed for the Sliding Menu ListView (the layout, the entity and the adapter).

Now, it’s time to implement it in the MainActivity with the following major steps:

  • Creating fragments for each Sliding Menu item
  • Create an instance of SlidingMenuAdapter and adding initial data
  • Assigning the adapter to Sliding Menu ListView
  • Handling on item click event to show the appropriate fragment for the clicked item

4. Create Fragments for each Sliding Menu items

Here, I only show to you the layout xml file and the code file of Home fragment. The others are similar and can be found in source code. Each fragment contains a TextView to describe the current screen. fragment_home.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#B8E62E">

    <TextView
        android:id="@+id/tv_home"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:text="Home"
        android:textAppearance="?android:attr/textAppearanceLarge" />

</RelativeLayout>

 

HomeFragment.java

public class HomeFragment extends Fragment {
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View rootView = inflater.inflate(R.layout.fragment_home, container, false);
        return rootView;
    }
}

 

5. MainActivity

Open MainActivity.java and implement the remaining major steps. The following code is the completed code for MainActivity. I noted so many comments there so you guys can understand it easily:

public class MainActivity extends Activity {
    private DrawerLayout drawerLayout;
    private ListView lvSlidingMenu;
    private ActionBarDrawerToggle drawerToggle; // Navigation Drawer titles 
    private CharSequence drawerTitle;
    private CharSequence appTitle;

    // Sliding Menu items 
    private String[] titles;
    private TypedArray icons;
    private ArrayList slidingMenuItems;
    private SlidingMenuAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        appTitle = drawerTitle = getTitle();

        // Load resources 
        titles = getResources().getStringArray(R.array.nav_drawer_items);
        icons = getResources().obtainTypedArray(R.array.nav_drawer_icons);

        // Get Sliding Menu ListView istance 
        drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        lvSlidingMenu = (ListView) findViewById(R.id.lv_sliding_menu);
        slidingMenuItems = new ArrayList();

        // Creating and Adding SlidingMenuItems 
        slidingMenuItems.add(new SlidingMenuItem(titles[0], icons.getResourceId(0, -1)));
        slidingMenuItems.add(new SlidingMenuItem(titles[1], icons.getResourceId(1, -1)));
        slidingMenuItems.add(new SlidingMenuItem(titles[2], icons.getResourceId(2, -1)));
        slidingMenuItems.add(new SlidingMenuItem(titles[3], icons.getResourceId(3, -1)));

        // Recycle the typed array 
        icons.recycle();
        lvSlidingMenu.setOnItemClickListener(new SlideMenuClickListener());

        // Assign adapter to listview 
        adapter = new SlidingMenuAdapter(getApplicationContext(), slidingMenuItems);
        lvSlidingMenu.setAdapter(adapter);

        // Enable action bar app icon and behaving it as toggle button 
        getActionBar().setDisplayHomeAsUpEnabled(true);
        getActionBar().setHomeButtonEnabled(true);
        drawerToggle = new ActionBarDrawerToggle(this, drawerLayout, R.drawable.ic_drawer,
                // Navigation Drawer 
                icon R.string.app_name,
                //Navigation Drawer open - description for accessibility 
                R.string.app_name
                // Navigation Drawer close - description for accessibility 
        ) {
            public void onDrawerClosed(View view) {
                getActionBar().setTitle(appTitle);
                invalidateOptionsMenu();
            }

            public void onDrawerOpened(View drawerView) {
                getActionBar().setTitle(drawerTitle);
                invalidateOptionsMenu();
            }
        }; drawerLayout.setDrawerListener(drawerToggle);
        if (savedInstanceState == null) {
            // On first time, show Home Fragment
            displayView(0);
        }
    }

    /**
     * Slide menu item click listener *
     */
    private class SlideMenuClickListener implements ListView.OnItemClickListener {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            // Display appropriate fragment for selected item 
            displayView(position);
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Toggle Navigation Drawer on selecting action bar app icon/title 
        if (drawerToggle.onOptionsItemSelected(item)) {
            return true;
        }
        // Handle action bar actions click 
        switch (item.getItemId()) {
            case R.id.action_settings:
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    } /* * * Called when invalidateOptionsMenu() is triggered */

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        // If Navigation Drawer is opened, hide the action items 
        boolean drawerOpen = drawerLayout.isDrawerOpen(lvSlidingMenu);
        menu.findItem(R.id.action_settings).setVisible(!drawerOpen);
        return super.onPrepareOptionsMenu(menu);
    }

    /**
     * Display fragment view for selected Navigation Drawer list item *
     */
    private void displayView(int position) {
        Fragment fragment = null;
        switch (position) {
            case 0:
                fragment = new HomeFragment();
                break;
            case 1:
                fragment = new NotificationsFragment();
                break;
            case 2:
                fragment = new SettingsFragment();
                break;
            case 3:
                fragment = new AboutFragment();
                break;
            default:
                break;
        }
        if (fragment != null) {
            FragmentManager fragmentManager = getFragmentManager();
            fragmentManager.beginTransaction().replace(R.id.fragment_detail, fragment).commit();

            // Update selected item and title, then close the drawer 
            lvSlidingMenu.setItemChecked(position, true);
            lvSlidingMenu.setSelection(position);
            setTitle(titles[position]);
            drawerLayout.closeDrawer(lvSlidingMenu);
        } else {
            // Log error
            Log.e("MainActivity", "Error in creating fragment");
        }
    }

    @Override
    public void setTitle(CharSequence title) {
        appTitle = title;
        getActionBar().setTitle(appTitle);
    }

    /**
     * When using the ActionBarDrawerToggle, you must call it during * onPostCreate() and onConfigurationChanged()...
     */
    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        // Sync the toggle state after onRestoreInstanceState has occurred. 
        drawerToggle.syncState();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        // Pass any configuration change to the drawer toggls 
        drawerToggle.onConfigurationChanged(newConfig);
    }
}

 

Run the project and enjoy: Android Sliding Menu

C - Download source code

https://drive.google.com/file/d/0Bw3dwdSezn6faXJYQW5ibG5zWnM/edit?usp=sharing