Introduction
In this post, we’ll take forward our learning on android material design. We’ll implement android sliding navigation drawer with material design. This sliding drawer will contain menu items. When we click on this menu items, corresponding app content view will open up in its own fragment.
In my previous blog, I have written about android material design concept, backward compatibility and we also developed a very basic app for demonstration purpose. We also learnt how to write customize theme. You may go through the same here –> Android Material Design Getting Started.
Tech Stack
In this tutorial, we’ll use followings –
1 2 |
Android Studio 3.0 JAVA for Android programming |
Create an app with Navigation Drawer Activity
- Launch Android Studio and click: File –> New –> New Project…
- A “Create New Project” dialog box will open; we’ll provide the app name and company domain. I have entered following details, you can provide the name/domain as per your choice and preference.
- Application Name:- ItcMaterialNavigationDrawer
- Company Domain:- iteritory.com
- Click on Next button. In the next window, select the minimum SDK version; you can choose as per your preference. In this case, I have chosen API 16: Android 4.1 (Jelly Bean). Click Next button.
- In the next window, select “Navigation Drawer Activity“. Click Next button.
- In the next window, let’s keep the Activity Name and Layout Name to default. Click Finish button.
- I’ll change the app name a bit here, traverse and open res–> values –> strings.xml. Find the line with app_name attribute. Change the value to “Nav Drawer“.
- Let’s run the app and observe the behavior. Please find below the app behavior in my system
- As you may have already noticed, this is a “Hello World!” app with a default navigation drawer. Navigation drawer has a header with a name “Android Studio” and an email id “android.studio@android.com”. You may have also noticed, the drawer has multiple menu items and also has a bottom section with 2 menu items.
- Let’s customize this navigation drawer with our requirement. Read on!!
Customize the navigation drawer header
- We’ll modify the following items –
- Change icon, name, email and color in the navigation header
- Change the menu items in drawer
Change icon, name and email in the navigation header
- Download the “account circle” icon from material.io website. I have downloaded 48dp, balck coloured, PNG formatted icon. You’ll have a zip file downloaded in your system.
- Extract the zip file and traverse to android subfolder. You will see multiple folders named like “drawable-hdpi” etc. In each of this folder, there is one version of the icon. We’ll copy each icon from each folder individually and paste to res–>mipmap folder in the studio. While pasting, ensure that you are selecting the right size subfolder inside mipmap folder. That means, if you are copying icon from drawable-hdpi, you will paste it to mipmap-hdpi folder.
- Traverse and open res –> layout–> nav_header_main.xml. We’ll change app:srcCompat attribute of imageView widget to @mipmap/ic_account_circle_black_48dp
- In the same xml file, we will search for the textview widget and change the android:text attribute to my name “Md Sadruddin”. You can give your name 🙂
- In the next textview widget, we’ll change the email id to “iteritorycom@gmail.com”
- All these can also be done programatically as well. However, that’s another day’s topic.
- Next, we’ll change the value of “android:background” of LinearLayout to @color/colorPrimary.
- So, after all the change, the nav_header_main.xml file looks like below –
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="@dimen/nav_header_height" android:background="@color/colorPrimary" android:gravity="bottom" android:orientation="vertical" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:theme="@style/ThemeOverlay.AppCompat.Dark"> <ImageView android:id="@+id/imageView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:paddingTop="@dimen/nav_header_vertical_spacing" app:srcCompat="@mipmap/ic_account_circle_black_48dp" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:paddingTop="@dimen/nav_header_vertical_spacing" android:text="Android Studio" android:textAppearance="@style/TextAppearance.AppCompat.Body1" /> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="iteritorycom@gmail.com" /> </LinearLayout> |
Change the menu items in drawer
- The existing menu items came by default along with the selected activity. However, it’s quite possible that you don’t want those menu items and you need other menu as per your own requirement. Let’s start customizing.
- In order to do so, we’ll again visit material design icon site to download few icons. Here, for this tutorial, I have downloaded below 5 icons in PNG format, black colored and all are of 36 dp –
- ic_chat
- ic_store
- ic_settings
- ic_contact_mail
- ic_contact_phone
- Post download, copy the icons of various sizes (hdpi, mdpi etc) from corresponding folders to the mipmap folder (exactly like you did few steps back)
- Traverse and open res–>menu–>activity_main_drawer.xml. Delete the existing menu items and add the ones we downloaded. After the necessary change, the content of this file will be –
123456789101112131415161718192021222324252627282930313233<?xml version="1.0" encoding="utf-8"?><menu xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"tools:showIn="navigation_view"><group android:checkableBehavior="single"><itemandroid:id="@+id/nav_store"android:icon="@mipmap/ic_store_black_36dp"android:title="Store" /><itemandroid:id="@+id/nav_chat"android:icon="@mipmap/ic_chat_black_36dp"android:title="Chat" /><itemandroid:id="@+id/nav_settings"android:icon="@mipmap/ic_settings_black_36dp"android:title="Settings" /></group><item android:title="Communicate"><menu><itemandroid:id="@+id/nav_contactmail"android:icon="@mipmap/ic_contact_mail_black_36dp"android:title="Mail Us" /><itemandroid:id="@+id/nav_contactphone"android:icon="@mipmap/ic_contact_phone_black_36dp"android:title="Call Us" /></menu></item></menu>
- Now, as we modified the menu, the same needs to reflected in the code as well. In order to do so, let’s open MainActivity.java file
- Create a new function displaySelectedFragment(int menuItemId) and make changes in onNavigationItemSelected(MenuItem item) to call the displaySelectedFragment function.
- After the change, the functions will be like –
123456789101112131415161718192021222324252627282930313233@SuppressWarnings("StatementWithEmptyBody")@Overridepublic boolean onNavigationItemSelected(MenuItem item) {// Handle navigation view item clicks here.displaySelectedFragment(item.getItemId());return true;}private void displaySelectedFragment(int menuItemId) {Fragment fragment = null;switch (menuItemId) {case R.id.nav_store://handle store fragmentbreak;case R.id.nav_chat://handle chatfragmentbreak;case R.id.nav_settings://handle settings fragmentbreak;default:break;}//replace the current fragmentif (fragment != null) {FragmentTransaction ft = getSupportFragmentManager().beginTransaction();ft.replace(R.id.content_frame, fragment);ft.commit();}DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);drawer.closeDrawer(GravityCompat.START);} - Run the app and reflect on the changes made so far.
Navigation Drawer Item Selection
You might have noticed that you are selecting the menu items properly, but there is no change in the app content. It’s always showing “Hello World!”. Now, we will make some code changes so that when we select a menu from navigation drawer, that menu specific content is displayed.
Here, we will demonstrate with 3 menu items (Store, Settings and Chat); hence, we’ll create one fragment class for each of these menu items. Follow the steps below –
- Right click on the “com.iteritory.itcmaterialnavigationdrawer” package and create a new package called “fragment“.
- Right click on the newly created package and select New –> Fragment –> Fragment (Blank). A new window will pop-up
- Set the fragment name as StoreFragment. Ensure to uncheck only followings –
- Include fragment factory method?
- Include interface callbacks?
- Click Finish button.
- This will also automatically create layout file as fragment_store.xml inside Layout directory.
- Change the StoreFragment.java to override onViewCreated funtion. After the modification the class will look like –
1234567891011121314151617181920212223242526272829303132333435package com.iteritory.itcmaterialnavigationdrawer.fragment;import android.os.Bundle;import android.support.annotation.Nullable;import android.support.v4.app.Fragment;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import com.iteritory.itcmaterialnavigationdrawer.R;/*** A simple {@link Fragment} subclass.*/public class StoreFragment extends Fragment {public StoreFragment() {// Required empty public constructor}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {// Inflate the layout for this fragmentreturn inflater.inflate(R.layout.fragment_store, container, false);}@Overridepublic void onViewCreated(View view, @Nullable Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);getActivity().setTitle("Store");}}
- Change the fragment_store.xml file content as below –
123456789101112131415<FrameLayout 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"tools:context="com.iteritory.itcmaterialnavigationdrawer.fragment.StoreFragment"><TextViewandroid:layout_width="match_parent"android:layout_height="match_parent"android:textAppearance="?android:attr/textAppearanceLarge"android:text="Hello!! This is Store Fragment"android:layout_centerVertical="true"android:layout_centerHorizontal="true" /></FrameLayout>
- Repeat the above steps for Settings and Chat menu items. Change “Store” with “Settings” and “Chat” as you create fragment class and layout XML respectively.
- Next, we’ll open res –> Layout –> content_main.xml and add a FrameLayout. This is the default frame layout that will be created while launching the app. This frame layout will then be replaced with the ones we created above as and when we select a particular menu from navigation drawer. After the change, the file looks like –
1234567891011121314151617<?xml version="1.0" encoding="utf-8"?><android.support.constraint.ConstraintLayout 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"app:layout_behavior="@string/appbar_scrolling_view_behavior"tools:context="com.iteritory.itcmaterialnavigationdrawer.MainActivity"tools:showIn="@layout/app_bar_main"><FrameLayoutandroid:id="@+id/container_frame"android:layout_width="match_parent"android:layout_height="match_parent" ></FrameLayout></android.support.constraint.ConstraintLayout> - Next, we will open MainActivity.java and further modify displaySelectedFragment function like below. This is to ensure we capture the menu selected from navigation drawer and then create corresponding fragment –
1234567891011121314151617181920212223242526private void displaySelectedFragment(int menuItemId) {Fragment fragment = null;switch (menuItemId) {case R.id.nav_store:fragment = new StoreFragment();break;case R.id.nav_chat:fragment = new ChatFragment();break;case R.id.nav_settings:fragment = new SettingsFragment();break;default:break;}//replace the current fragmentif (fragment != null) {FragmentTransaction ft = getSupportFragmentManager().beginTransaction();ft.replace(R.id.content_frame, fragment);ft.commit();}DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);drawer.closeDrawer(GravityCompat.START);} - After all these changes, let’s take a look at how MainActivity class will look like –
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118package com.iteritory.itcmaterialnavigationdrawer;import android.os.Bundle;import android.support.design.widget.FloatingActionButton;import android.support.design.widget.Snackbar;import android.support.v4.app.Fragment;import android.support.v4.app.FragmentTransaction;import android.view.View;import android.support.design.widget.NavigationView;import android.support.v4.view.GravityCompat;import android.support.v4.widget.DrawerLayout;import android.support.v7.app.ActionBarDrawerToggle;import android.support.v7.app.AppCompatActivity;import android.support.v7.widget.Toolbar;import android.view.Menu;import android.view.MenuItem;import com.iteritory.itcmaterialnavigationdrawer.fragment.ChatFragment;import com.iteritory.itcmaterialnavigationdrawer.fragment.SettingsFragment;import com.iteritory.itcmaterialnavigationdrawer.fragment.StoreFragment;public class MainActivity extends AppCompatActivityimplements NavigationView.OnNavigationItemSelectedListener {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);setSupportActionBar(toolbar);FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);fab.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG).setAction("Action", null).show();}});DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);drawer.addDrawerListener(toggle);toggle.syncState();NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);navigationView.setNavigationItemSelectedListener(this);}@Overridepublic void onBackPressed() {DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);if (drawer.isDrawerOpen(GravityCompat.START)) {drawer.closeDrawer(GravityCompat.START);} else {super.onBackPressed();}}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}@Overridepublic 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 SimplifiableIfStatementif (id == R.id.action_settings) {return true;}return super.onOptionsItemSelected(item);}@SuppressWarnings("StatementWithEmptyBody")@Overridepublic boolean onNavigationItemSelected(MenuItem item) {// Handle navigation view item clicks here.displaySelectedFragment(item.getItemId());return true;}private void displaySelectedFragment(int menuItemId) {Fragment fragment = null;switch (menuItemId) {case R.id.nav_store:fragment = new StoreFragment();break;case R.id.nav_chat:fragment = new ChatFragment();break;case R.id.nav_settings:fragment = new SettingsFragment();break;default:break;}//replace the current fragmentif (fragment != null) {FragmentTransaction ft = getSupportFragmentManager().beginTransaction();ft.replace(R.id.container_frame, fragment);ft.commit();}DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);drawer.closeDrawer(GravityCompat.START);}}
- Now, run the program. This app will run in most modern android device with latest OS version, as well as any device with API level 16.
Demo of the app
Download Code
Should you like to clone or download the code, hit github here –> https://github.com/msadrud/ItcMaterialNavigationDrawer