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 –
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 –
<?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 –
<?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"> <item android:id="@+id/nav_store" android:icon="@mipmap/ic_store_black_36dp" android:title="Store" /> <item android:id="@+id/nav_chat" android:icon="@mipmap/ic_chat_black_36dp" android:title="Chat" /> <item android:id="@+id/nav_settings" android:icon="@mipmap/ic_settings_black_36dp" android:title="Settings" /> </group> <item android:title="Communicate"> <menu> <item android:id="@+id/nav_contactmail" android:icon="@mipmap/ic_contact_mail_black_36dp" android:title="Mail Us" /> <item android: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 –
@SuppressWarnings("StatementWithEmptyBody") @Override public 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 fragment break; case R.id.nav_chat: //handle chatfragment break; case R.id.nav_settings: //handle settings fragment break; default: break; } //replace the current fragment if (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 –
package 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 } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment return inflater.inflate(R.layout.fragment_store, container, false); } @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); getActivity().setTitle("Store"); } }
- Change the fragment_store.xml file content as below –
<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"> <TextView android: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 –
<?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"> <FrameLayout android: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 –
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 fragment if (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 –
package 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 AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener { @Override protected 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() { @Override public 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); } @Override public void onBackPressed() { DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout); if (drawer.isDrawerOpen(GravityCompat.START)) { drawer.closeDrawer(GravityCompat.START); } else { super.onBackPressed(); } } @Override public 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; } @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); } @SuppressWarnings("StatementWithEmptyBody") @Override public 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 fragment if (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