164

Google introduced the NavigationView in the Design Support Library version 22.2.0 with which you can create a drawer very easily using a menu resource.

How can I create a simple divider line between two items? Grouping the items didn't work. Creating a sub items section does create a divider line, but it requires a title, which I don't want.

Any help would be appreciated.

N J
  • 27,217
  • 13
  • 76
  • 96
Longi
  • 3,913
  • 2
  • 28
  • 38
  • As stated in the comments to it, the problem with the accepted answer is, that the checkable behavior doesn't work across multiple (parallel) groups. To avoid this, do not create parallel groups, but use sub menus or sub groups to get your dividers as described in my answer here: http://stackoverflow.com/questions/30766919/how-to-set-shared-checkable-behavior-across-all-groups-in-navigationview/33877051#33877051 – Till - Appviewer.io Nov 24 '15 at 23:12

14 Answers14

337

All you need to do is define a group with an unique ID, I have checked the implementation if group has different id's it will create a divider.

Example menu, creating the separator:

<menu 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"
    tools:context=".MainActivity">

    <group android:id="@+id/grp1" android:checkableBehavior="single" >
        <item
            android:id="@+id/navigation_item_1"
            android:checked="true"
            android:icon="@drawable/ic_home"
            android:title="@string/navigation_item_1" />
    </group>

    <group android:id="@+id/grp2" android:checkableBehavior="single" >
        <item
            android:id="@+id/navigation_item_2"
            android:icon="@drawable/ic_home"
            android:title="@string/navigation_item_2" />
    </group>
</menu>
Rob
  • 26,989
  • 16
  • 82
  • 98
N J
  • 27,217
  • 13
  • 76
  • 96
  • i upvoted it @Nilesh , i just want to get information, that what is NavigationView,? and is it like Navigation Drawer? can you give information..just want to know – Ajay P. Prajapati Jun 03 '15 at 16:44
  • Yes @AjayP.Prajapati you can always check this blog for new things in android http://android-developers.blogspot.in/2015/05/android-design-support-library.html – N J Jun 03 '15 at 16:47
  • 9
    Wonder why this is (as far as I know) not documented. I think it will be asked a lot. Thanks! – Gaëtan Jun 03 '15 at 17:32
  • 16
    The one problem with this approach is that `setChecked` seems to work at the group level. If you select an item in Group A, then open the drawer again and select item in Group B, both items will remain highlighted. Maybe Google will fix this behavior in the next release, but for now, that's the downside of using multiple groups with NavigationView. – hungryghost Jun 04 '15 at 09:28
  • 1
    @hungryghost yes this is just preview, definitely Google will fixed it – N J Jun 04 '15 at 09:33
  • 1
    @hungryghost you can manually unselect items in a listener as a workaround – Longi Jun 04 '15 at 10:51
  • Set `0dp` to remove the padding when you do this unless you want each group to have padding. – Dan Brough Jul 10 '15 at 04:40
  • 3
    Great. About the double checked, try `android:checkableBehavior="none"` for your second group (that are actions, not navigation, I assume) – espinchi Jul 23 '15 at 12:07
  • 1
    how to add selected BG color? – John Sep 22 '15 at 07:18
  • problem with this is when we are marking the item as checked, the bg for checked item doesn`t shows from one separator to other. empty space is shown which looks bad – binaryKarmic Jan 18 '16 at 12:38
  • Update : adding 0dp in dimens.xml solves the issue. Yay ! – binaryKarmic Jan 20 '16 at 12:13
  • 12
    Funny thing, if you remove the id from the `group` it will compile and run but the dividers are hidden. – Vahid Amiri Feb 08 '16 at 07:04
  • 1
    divider adds extra padding. how to remove that padding? – Zahan Safallwa Jul 15 '16 at 09:29
  • 1
    @ZahanSafallwa see this answer http://stackoverflow.com/questions/38519293/reduce-space-between-menu-groups-inside-navigation-drawer/38519594#38519594 – N J Jul 22 '16 at 07:04
  • 5
    This does not work for me either. I wanted lines between the menu groups, not after each item. – Rich Morey Mar 10 '17 at 21:50
  • Does not work for me, it just add checkbox for each item, not divider. – zeleven Jan 17 '18 at 09:55
  • How to adjust gaps between Icon and the Title for the items ? – Abhishek Sengupta Jul 21 '18 at 06:08
  • I can't believe this is the selected answer with a lot of upvotes. It's so hacky. – ataravati Jul 02 '19 at 18:15
61

create a drawable drawer_item_bg.xml like this,

    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">

    <item>
        <shape android:shape="rectangle" >
            <solid android:color="#F4F4F4" />
        </shape>
    </item>

    <item android:top="-2dp" android:right="-2dp" android:left="-2dp">
        <shape>
            <solid android:color="@android:color/transparent" />
            <stroke
                android:width="1dp"
                android:color="#EAEAEA" />
        </shape>
        <!--
        android:dashGap="10px"
                android:dashWidth="10px"
                -->
    </item>

</layer-list>

and add it to NavigationView as app:itemBackground="@drawable/drawer_item_bg"

<android.support.design.widget.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:background="#F4F4F4"
        android:layout_gravity="start"
        android:fitsSystemWindows="false"
        app:menu="@menu/activity_main_drawer"
        app:itemBackground="@drawable/drawer_item_bg"/>

and here we go...enter image description here

Mehul Solanki
  • 1,147
  • 11
  • 15
vbp
  • 1,157
  • 10
  • 16
  • 1
    this works, but it also removes the left padding of item icon. at least in my code, not in your screenshot for some reason – luky Dec 14 '16 at 08:40
  • @vbp I need the top border for first child, bottom border for other child. How could I achieve. It is something similar to id.first child in css – Prabs Feb 13 '17 at 07:06
  • @Prabs consider using a fragment ,recyclerview or custom views instead of NavigationView for better customization – vbp Feb 23 '17 at 11:18
  • 1
    I've done `navMenuView.addItemDecoration(new DividerItemDecoration(NavigationViewActivity.this, DividerItemDecoration.VERTICAL));` for perfect item border – Prabs Feb 27 '17 at 05:39
23

You can add dividers easily by setting Menu Item Background via XML using app:itemBackground

<android.support.design.widget.NavigationView
    android:id="@id/drawer_navigation_view"
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:fitsSystemWindows="true"
    app:menu="@menu/all_navigation_menu"
    app:itemIconTint="@color/colorPrimary"
    app:itemBackground="@drawable/bg_drawer_item"
    android:background="@color/default_background"/>

And use LayerDrawable as the background. It preserves material design ripple overlay for clicks.

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="@color/white"/>
        </shape>
    </item>
    <item android:left="@dimen/activity_horizontal_margin">
        <shape android:shape="rectangle">
            <solid android:color="@color/divider"/>
        </shape>
    </item>
    <item android:bottom="1dp">
        <shape android:shape="rectangle">
            <solid android:color="@color/white"/>
        </shape>
    </item>
</layer-list>

The result:

enter image description here

20

Simple add DeviderItemDecoration :

NavigationView navigationView = (NavigationView) findViewById(R.id.navigation);
NavigationMenuView navMenuView = (NavigationMenuView) navigationView.getChildAt(0);
navMenuView.addItemDecoration(new DividerItemDecoration(MainActivity.this,DividerItemDecoration.VERTICAL));

It look like this :

enter image description here

SANAT
  • 8,489
  • 55
  • 66
  • Can I change the height of `addItemDecoration` line to 1px? – Prabs Feb 13 '17 at 07:16
  • Thank you your solution worked for me. I appreciate. Bro one more question with this. Is it possible to remove the top border for the first item and set borders only to the bottom of the items? – viper Mar 14 '17 at 07:07
  • @viper please refer this : https://www.bignerdranch.com/blog/a-view-divided-adding-dividers-to-your-recyclerview-with-itemdecoration/ – SANAT Mar 15 '17 at 09:58
  • 2
    That kind of divider for each item not follow Material Guyidelines – Bo Z Apr 26 '19 at 00:19
11

I think I have an even better solution for the problem of multiple checked items. Using my way you don't have to worry about changing your code when adding new sections to your menu. My menu looks just like the accepted solution written by Jared, with the difference of using andoid:checkableBehavior="all" on the groups:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group android:id="@+id/first_section" android:checkableBehavior="all">
        <item
            android:id="@+id/frontpage"
            android:icon="@drawable/ic_action_home_24dp_light_blue"
            android:title="@string/drawer_frontpage" />
        <item
            android:id="@+id/search"
            android:icon="@drawable/ic_search"
            android:title="@string/drawer_search" />
    </group>
    <group android:id="@+id/second_section" android:checkableBehavior="all">
        <item
            android:id="@+id/events"
            android:icon="@drawable/ic_maps_local_movies_24dp_light_blue"
            android:title="@string/drawer_events" />
    </group>
</menu>

The checkableBehavior of 'all' makes it possible to check/uncheck single items at will, independently from which group they belong to. You just have to store the last checked menuitem. The java-code looks like this:

private MenuItem activeMenuItem;

@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
    // Update selected/deselected MenuItems
    if (activeMenuItem != null)
        activeMenuItem.setChecked(false);
    activeMenuItem = menuItem;
    menuItem.setChecked(true);

    drawerLayout.closeDrawers();
    return true;
}
plexus
  • 1,728
  • 1
  • 16
  • 12
10

I'm not sure if this is fixed in API 26 (Android 8) or it was possible all the time. I'm still a noob in Android programming. However I added parent groups as below. Testing on Android 6 physical phone,

  1. I have the divider
  2. Selecting any item from either nav_g1 or nav_g2 will deselect other items.
  3. No extra padding added due to nested groups.
  4. I didn't add any Java code to listeners

Menu Code

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group android:checkableBehavior="single">
        <group
            android:id="@+id/nav_g1"
            android:checkableBehavior="single">
            <item
                android:id="@+id/nav_1"
                android:icon="@drawable/ic_menu_share"
                android:title="@string/nav_1"/>
            <item
                android:id="@+id/nav_2"
                android:icon="@drawable/ic_menu_share"
                android:title="@string/nav_2"/>
        </group>
        <group
            android:id="@+id/nav_g2"
            android:checkableBehavior="single">
            <item
                android:id="@+id/nav_3"
                android:icon="@drawable/ic_menu_share"
                android:title="@string/nav_3"/>
            <item
                android:id="@+id/nav_4"
                android:icon="@drawable/ic_menu_share"
                android:title="@string/nav_4"/>
        </group>
    </group>
    <item android:title="Actions">
        <menu>
            <item
                android:id="@+id/nav_7"
                android:icon="@drawable/ic_menu_share"
                android:title="@string/nav_7"/>
            <item
                android:id="@+id/nav_8"
                android:icon="@drawable/ic_menu_share"
                android:title="@string/nav_8"/>
        </menu>
    </item>
</menu>

Notes

  1. As mentioned in this answer each group need to have a unique Id to show the divider.
  2. As per this answer spaces are matching the google material design specs.
  3. Having android:checkableBehavior="single" for parent group is required so the problem of multiple selected menu items in this answer (mentioned in comments by hungryghost) does not happen

And here is the screenshot

Screenshot of the device screen

AaA
  • 3,600
  • 8
  • 61
  • 86
8

Making different groups like Nilesh's answer does make a divider in between But creates the problem of two checked items in the nav drawer.

A simple way how I handled this was:

    public boolean onNavigationItemSelected(final MenuItem menuItem) {

    //if an item from extras group is clicked,refresh NAV_ITEMS_MAIN to remove previously checked item
    if (menuItem.getGroupId() == NAV_ITEMS_EXTRA) {


        navigationView.getMenu().setGroupCheckable(NAV_ITEMS_MAIN, false, true);
        navigationView.getMenu().setGroupCheckable(NAV_ITEMS_EXTRA, true, true);
       }else{

        navigationView.getMenu().setGroupCheckable(NAV_ITEMS_MAIN, true, true);
        navigationView.getMenu().setGroupCheckable(NAV_ITEMS_EXTRA, false, true);


    }
    //Update highlighted item in the navigation menu
    menuItem.setChecked(true);
}
Zorawar Sachdev
  • 334
  • 1
  • 4
  • Even simpler: `android:checkableBehavior="none"` – espinchi Jul 23 '15 at 12:05
  • 2
    @espinchi - That will not work if other groups contain navigation menu items. This solution could work for actions only. Not good UX practice – Mushtaq Jameel Jul 26 '15 at 19:54
  • Excellent! It might be clearer if you changed your undefined constants NAV_ITEMS_MAIN and NAV_ITEMS_EXTRA with R.id.nav_items_group_main or R.id.nav_items_group_extra and add the required XML to your example – ChrisPrime Aug 04 '15 at 20:05
  • IS onNavigationItemSelected(final MenuItem menuItem) { Default method?? where should i do this code? – John Sep 22 '15 at 07:27
  • and what is NAV_ITEMS_MAIN?? – John Sep 22 '15 at 07:31
  • @John - Yes, it is the default implemented method of NavigationView.OnNavigationItemSelectedListener NAV_ITEMS_MAIN is just the R.id. of the menuItem's group,eg: in menu.xml its R.id.groupIdMain – Zorawar Sachdev Sep 23 '15 at 07:55
  • @ZorawarSachdev Thank you so much default method is very clear i have implemented it. Another doubt is – John Sep 23 '15 at 08:55
  • With Support Library 23.1.0 this fix is no longer needed at all. Setting android:checkableBehavior="single" in both groups keeps only one item checked from both groups. – sorianiv Nov 08 '15 at 21:53
5

I wanted dividers above the first item and after the last item. Using @Nilesh solution I had to add dummy menu items and set enabled to false which felt really dirty. Plus what if I want to do other cool stuff in my menu?

I noticed the NavigationView extends FrameLayout so you can put your own content into it just like you would for a FrameLayout. I then set an empty menu xml so that it only shows my custom layout. I understand that this probably goes against the path Google wants us to take but if you want a truly custom menu this is an easy way to do it.

<!--Note: NavigationView extends FrameLayout so we can put whatever we want in it.-->
<!--I don't set headerLayout since we can now put that in our custom content view-->
<android.support.design.widget.NavigationView
    android:layout_width="wrap_content"
    android:layout_height="match_parent"
    android:layout_gravity="start"
    android:fitsSystemWindows="true"
    app:menu="@menu/empty_menu">

    <!--CUSTOM CONTENT-->
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <!-- CUSTOM HEADER -->
        <include
            android:id="@+id/vNavigationViewHeader"
            layout="@layout/navigation_view_header"/>

        <!--CUSTOM MENU-->
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:layout_below="@+id/vNavigationViewHeader">

            <View style="@style/NavigationViewLineSeperator"/>

            <Button android:text="Option 1"/>

            <View style="@style/NavigationViewLineSeperator"/>

            <Button android:text="Option 2"/>

            <View style="@style/NavigationViewLineSeperator"/>

        </LinearLayout>
    </RelativeLayout>
</android.support.design.widget.NavigationView>

Here is the style

<style name="NavigationViewLineSeperator">
        <item name="android:background">@drawable/line_seperator</item>
        <item name="android:layout_width">match_parent</item>
        <item name="android:layout_height">1dp</item>
</style>

And drawable

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">

    <solid android:color="@color/white"/>
    <size android:width="100sp"
          android:height="1sp" />
</shape>

And the menu

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
</menu>

edit:

Instead of Buttons you can use TextView with drawable which mimics the original menu items look:

 <TextView
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:text="@string/menu_support"
     android:drawableLeft="@drawable/menu_icon_support"
     style="@style/MainMenuText" />

// style.xml
<style name="MainMenuText">
    <item name="android:drawablePadding">12dp</item>
    <item name="android:padding">10dp</item>
    <item name="android:gravity">center_vertical</item>
    <item name="android:textColor">#fff</item>
</style>
luky
  • 2,263
  • 3
  • 22
  • 40
Justin Fiedler
  • 6,478
  • 3
  • 21
  • 25
  • 1
    thanks, apparently the most convenient way of having custom views as menu items – Jan Rabe Sep 17 '15 at 17:30
  • i use this solution also because it lets me more easy set the custom font of items and change the divider color – luky Dec 14 '16 at 10:25
1

Credit should go to Zorawar for the solution, Sorry for duplicating the answer but could not add so much formatted text within a comment.

Zorawar's solution works, the code could be improved as such :

public void onNavigationItemSelected(int groupId) {

    //if an item from extras group is clicked,refresh NAV_ITEMS_MAIN to remove previously checked item
    navigationView.getMenu().setGroupCheckable(NAV_ITEMS_MAIN, (groupId == NAV_ITEMS_MAIN), true);
    navigationView.getMenu().setGroupCheckable(NAV_ITEMS_EXTRA, (groupId == NAV_ITEMS_EXTRA), true);


    //Update highlighted item in the navigation menu
    menuItem.setChecked(true);
}
Mushtaq Jameel
  • 7,053
  • 7
  • 33
  • 52
1

Call requires API level 28 :

just use

 menu?.setGroupDividerEnabled(true)

in onCreateOptionsMenu function

Example :

override fun onCreateOptionsMenu(menu: Menu?): Boolean {

        menuInflater.inflate(R.menu.main_menu, menu)

        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
            menu?.setGroupDividerEnabled(true)
        }
        
        return super.onCreateOptionsMenu(menu)


    }
Xlife
  • 21
  • 2
0

Nileh's Answer is right , Except it has one flaw of double checking.

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">

    <group android:checkableBehavior="single" android:id="@+id/grp1">
        <item
            android:id="@+id/nav_register_customer"
            android:icon="@drawable/ic_menu_camera"
            android:checkableBehavior="none"
            android:title="Register Customer" />
    </group>
    <group  android:id="@+id/grp2"
        android:checkableBehavior="single"  >
        <item
            android:id="@+id/nav_slideshow"
            android:icon="@drawable/ic_menu_slideshow"
            android:checkableBehavior="none"
            android:title="Slideshow" />
    </group>
</menu>

So using

android:checkableBehavior="single"

with unique id shall solve the problem

Ajji
  • 3,068
  • 2
  • 30
  • 31
0

If you want to add divider dynamically, you can just add an empty SubMenu like this:

Menu menu = navigationView.getMenu();
menu.addSubMenu(" ").add(" ");

this will add a divider.

just be sure to pass in the right index when using menu.getItem(int index)

Moh Mah
  • 2,005
  • 20
  • 29
0

In addition to previous answers if you do want decorative separators but don't want to create multiple groups because of "checkable behavior" problems - you can assign the same group id to all your groups.

Example:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group
    android:id="@+id/group_nav_common" <!-- New group id-->
    android:checkableBehavior="single">

    <item
        android:id="@+id/menu_item_nav_home"
        android:icon="@drawable/ic_home_black_24dp"
        android:title="@string/nav_menu_main" />
    <item
        android:id="@+id/menu_item_nav_articles"
        android:icon="@drawable/ic_art_track_black_24dp"
        android:title="@string/latest_news" />

    <item
        android:id="@+id/menu_item_nav_group_categories"
        android:title="@string/nav_menu_sections">
        <menu>
            <group
                android:id="@id/group_nav_common" <!-- Existing group id -->
                android:checkableBehavior="single">
                <!-- Programmatically populated section -->
            </group>
        </menu>
    </item>

    <item
        android:id="@+id/menu_item_nav_group_sites"
        android:title="@string/nav_menu_sites">
        <menu>
            <group
                android:id="@id/group_nav_common" <!-- Existing group id -->
                android:checkableBehavior="single">
                <item
                    android:id="@+id/menu_item_nav_select_site"
                    android:icon="@drawable/ic_account_balance_black_24dp"
                    android:title="@string/nav_menu_select_site" />
            </group>
        </menu>
    </item>
</group>

ievgen
  • 1,081
  • 11
  • 20
0

If the selected answer not work for you, you may want to try adding this to onCreateOptionsMenu in addition to give the unique group id:

if (Build.VERSION.SDK_INT >= 28) {
    menu.setGroupDividerEnabled(true)
}
user806696
  • 19
  • 2