如何在新的NavigationView中创建一个简单的分隔线?


154

Google NavigationView在设计支持库版本22.2.0中引入,您可以使用菜单资源非常轻松地创建抽屉。

如何在两个项目之间创建一条简单的分隔线?将项目分组不起作用。创建子项部分的确会创建分隔线,但是它需要标题,而我并不需要。

任何帮助,将不胜感激。


如对其评论中所述,可接受答案的问题是,可检查行为不适用于多个(并行)组。为避免这种情况,请不要创建并行组,而是使用子菜单或子组来获取分隔符,如我在此处的答案所述:stackoverflow.com/questions/30766919/…–
直到

Answers:


319

您需要做的就是定义一个group具有唯一ID的,我已经检查了实现是否组具有不同的ID,这将创建一个分隔符。

示例菜单,创建分隔符:

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

9
想知道为什么(据我所知)为什么没有记录。我认为这会被问很多。谢谢!
盖坦2015年

16
这种方法的一个问题是,它setChecked似乎在小组级别上起作用。如果您在A组中选择一个项目,然后再次打开抽屉并在B组中选择一个项目,则两个项目都将保持突出显示状态。也许Google会在下一个版本中解决此问题,但是就目前而言,这是在NavigationView中使用多个组的不利之处。
hungryghost

3
大。关于再次检查,请尝试android:checkableBehavior="none"第二小组(我认为是行动,而不是导航)
espinchi 2015年

12
有趣的是,如果您从中删除ID,group它将编译并运行,但分隔符是隐藏的。
Vahid Amiri

5
这对我也不起作用。我想要菜单组之间的行,而不是每个项目之后。
Rich Morey

54

像这样创建一个可绘制的drawer_item_bg.xml

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

并将其作为app:itemBackground =“ @ drawable / drawer_item_bg”添加到NavigationView

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

现在我们开始...在此处输入图片说明


1
这行得通,但同时也删除了项目图标的左侧填充。至少在我的代码,而不是在你的屏幕截图出于某种原因
luky

@vbp我需要第一个孩子的顶部边框,其他孩子的底部边框。我该如何实现。这类似于ids.css中的第一个孩子
Prabs

@Prabs考虑使用片段,recyclerview或自定义视图来代替NavigationView,以实现更好的自定义
vbp

1
我已经navMenuView.addItemDecoration(new DividerItemDecoration(NavigationViewActivity.this, DividerItemDecoration.VERTICAL));为完美的物品边框做过
Prabs

19

简单添加DeviderItemDecoration:

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

看起来像这样:

在此处输入图片说明


我可以将addItemDecoration线的高度更改为1px吗?
Prabs

谢谢您的解决方案为我工作。我很感激 兄弟另一个问题。是否可以删除第一个项目的顶部边框,而仅将边界设置为项目的底部?
毒蛇

@viper,请参阅:bignerdranch.com/blog/…–
SANAT

1
每种项目的分隔线都没有遵循Material Guyidelines
Boris Ruzanov

19

您可以使用XML通过设置菜单项背景来轻松添加分隔线 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"/>

并使用LayerDrawable作为背景。它保留了咔嗒声的材料设计波纹叠层。

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

结果:

在此处输入图片说明


2
似乎是最好的答案,并没有参与团体
米哈尔Ziobro

如果要为所选项目使用自定义背景色怎么办?
ataravati

我有<形状>一个错误:元素此处不允许
塞巴斯蒂安REMY

11

我认为对于多重检查项目,我有一个更好的解决方案。使用我的方式,在菜单上添加新部分时,您不必担心更改代码。我的菜单看起来就像Jared所接受的解决方案,区别在于在组上使用andoid:checkableBehavior =“ all ”:

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

all的checkableBehavior使得可以随意检查/取消检查单个项目,而与它们属于哪个组无关。您只需要存储最后检查的菜单项。Java代码如下所示:

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;
}

8

像Nilesh的答案那样划分不同的组确实可以在两者之间进行分隔,但是会在导航抽屉中产生两个已选中项目的问题。

我处理此问题的简单方法是:

    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);
}

更简单:android:checkableBehavior="none"
espinchi

2
@espinchi-如果其他组包含导航菜单项,则将无法使用。此解决方案仅适用于操作。不好的用户体验做法
Mushtaq Jameel,2015年

优秀的!如果您使用R.id.nav_items_group_main或R.id.nav_items_group_extra更改未定义的常量NAV_ITEMS_MAIN和NAV_ITEMS_EXTRA并将所需的XML添加到您的示例中,可能会更清楚
ChrisPrime,2015年

IS onNavigationItemSelected(final MenuItem menuItem){默认方法?我应该在哪里执行此代码?
约翰

什么是NAV_ITEMS_MAIN?
约翰

8

我不确定这是固定的API 26 (Android 8)还是一直存在。我仍然是Android编程的新手。但是,我添加了以下父组。在Android 6实体电话上进行测试,

  1. 我有分隔线
  2. nav_g1或中选择任何一项nav_g2将取消选择其他项。
  3. 由于嵌套的组,没有添加额外的填充。
  4. 我没有Java向侦听器添加任何代码

菜单代码

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

笔记

  1. 答案所述,每个组都需要具有唯一的ID才能显示分隔符。
  2. 按照这个答案空间是匹配谷歌材料设计规范。
  3. 必须有一个android:checkableBehavior="single"父组,这样就不会发生答案中多个选定菜单项的问题(在hungryghost的注释中提到)

这是屏幕截图

设备屏幕截图


5

我想要在第一项之后和最后一项之后的分隔线。使用@Nilesh解决方案,我必须添加虚拟菜单项,并将enable设置为false,这真的很脏。另外,如果我想在菜单中做其他很棒的事情,该怎么办?

我注意到NavigationView扩展了FrameLayout,因此您可以像使用FrameLayout一样将自己的内容放入其中。然后,我设置一个空菜单xml,使其仅显示我的自定义布局。我了解这可能与Google希望我们采取的方法背道而驰,但是如果您想要真正定制的菜单,这是一种简便的方法。

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

这是风格

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

和可绘制

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

和菜单

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

编辑:

可以使用TextView和drawable来代替Button,它可以模仿原始菜单项的外观:

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

1
谢谢,显然是将自定义视图作为菜单项的最便捷方法
Jan Rabe 2015年

我也使用此解决方案是因为它使我可以更轻松地设置项目的自定义字体并更改分隔线的颜色
luky

1

值得赞扬的应该是Zorawar提供的解决方案,对不起,您需要重复答案,但不能在评论中添加太多格式的文本。

Zorawar的解决方案有效,代码可以这样改进:

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);
}

什么是NAV_ITEMS_MAIN和NAV_ITEMS_EXTRA和groupid?
约翰

它们是group_id的常数
Mushtaq Jameel

0

Nileh的答案是正确的,除了它具有双重检查的缺陷。

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

所以用

android:checkableBehavior =“ single”

具有唯一标识的ID将解决问题


0

如果要动态添加分隔线,则可以仅添加一个空的SubMenu,如下所示:

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

这将添加一个分隔线。

只要确保在使用时传递正确的索引 menu.getItem(int index)


0

除了以前的答案之外,如果您确实想要装饰性分隔符但又由于“可检查的行为”问题而不想创建多个组,则可以为所有组分配相同的组ID。

例:

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


0

如果所选答案对您不起作用,则onCreateOptionsMenu除了提供唯一的组ID外,您可能还想尝试将其添加到:

if (Build.VERSION.SDK_INT >= 28) {
    menu.setGroupDividerEnabled(true)
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.