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

Posted

技术标签:

【中文标题】如何在新的 NavigationView 中创建一个简单的分隔线?【英文标题】:How to create a simple divider in the new NavigationView? 【发布时间】:2015-08-17 23:15:36 【问题描述】:

Google 在 Design Support Library 版本 22.2.0 中引入了NavigationView,您可以使用菜单资源非常轻松地创建抽屉。

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

任何帮助将不胜感激。

【问题讨论】:

如 cmets 中所述,已接受答案的问题是,可检查的行为不适用于多个(并行)组。为避免这种情况,请不要创建并行组,而是使用子菜单或子组来获取您的分隔符,如我在此处的回答中所述:***.com/questions/30766919/… 【参考方案1】:

您需要做的就是定义一个带有唯一 IDgroup,我已经检查了实现,如果组有不同的 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>

【讨论】:

想知道为什么(据我所知)没有记录。我想它会被问到很多。谢谢! 这种方法的一个问题是setChecked 似乎在组级别上工作。如果您选择 A 组中的一个项目,然后再次打开抽屉并选择 B 组中的项目,这两个项目将保持突出显示。也许 Google 会在下一个版本中修复此行为,但目前,这是在 NavigationView 中使用多个组的缺点。 太棒了。关于双重检查,请为您的第二组尝试android:checkableBehavior="none"(我认为这是操作,而不是导航) 有趣的是,如果您从 group 中删除 id,它将编译并运行,但分隔符是隐藏的。 这对我也不起作用。我想要菜单组之间的线条,而不是每个项目之后。【参考方案2】:

像这样创建一个可绘制的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:
                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_
        android:layout_
        android:background="#F4F4F4"
        android:layout_gravity="start"
        android:fitsSystemWindows="false"
        app:menu="@menu/activity_main_drawer"
        app:itemBackground="@drawable/drawer_item_bg"/>

我们开始...

【讨论】:

这可行,但它也删除了项目图标的左侧填充。至少在我的代码中,而不是出于某种原因在您的屏幕截图中 @vbp 我需要第一个孩子的顶部边框,其他孩子的底部边框。我怎么可能达到。它类似于 id.first child in css @Prabs 考虑使用片段、recyclerview 或自定义视图而不是 NavigationView 以获得更好的自定义效果 我已经完成了navMenuView.addItemDecoration(new DividerItemDecoration(NavigationViewActivity.this, DividerItemDecoration.VERTICAL)); 的完美项目边框【参考方案3】:

您可以通过 XML 使用 app:itemBackground 设置菜单项背景轻松添加分隔符

<android.support.design.widget.NavigationView
    android:id="@id/drawer_navigation_view"
    android:layout_
    android:layout_
    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作为背景。它保留了 Material Design 波纹叠加层以供点击。

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

结果:

【讨论】:

似乎是最好的答案,没有涉及任何团体 如果要为所选项目使用自定义背景颜色怎么办? 我在 上有一个错误:此处不允许元素【参考方案4】:

简单添加DeviderItemDecoration:

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

看起来像这样:

【讨论】:

我可以将addItemDecoration行的高度改为1px吗? 感谢您的解决方案对我有用。我很感激。兄弟还有一个问题。是否可以删除第一个项目的顶部边框并仅将边框设置到项目的底部? @viper 请参考:bignerdranch.com/blog/… 每个项目的那种分隔线不遵循材料准则【参考方案5】:

我想我有一个更好的解决方案来解决多个检查项目的问题。使用我的方式,在向菜单添加新部分时,您不必担心更改代码。 我的菜单看起来就像 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;

【讨论】:

【参考方案6】:

我不确定API 26 (Android 8) 中是否已解决此问题,或者一直都有可能。我仍然是 Android 编程的菜鸟。但是,我添加了父组,如下所示。在Android 6 实体手机上测试,

    我有分隔线 从nav_g1nav_g2 中选择任何项目将取消选择其他项目。 由于嵌套组,没有添加额外的填充。 我没有向侦听器添加任何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>

备注

    正如this 回答中提到的,每个组都需要有一个唯一的 ID 来显示分隔符。 根据this,答案空间符合谷歌材料设计规范。 父组需要android:checkableBehavior="single",因此this 答案中的多个选定菜单项的问题(hengghost 在 cmets 中提到)不会发生

这是截图

【讨论】:

【参考方案7】:

像 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 - 如果其他组包含导航菜单项,这将不起作用。此解决方案仅适用于操作。不好的用户体验实践 太棒了!如果您将未定义的常量 NAV_ITEMS_MAIN 和 NAV_ITEMS_EXTRA 更改为 R.id.nav_items_group_main 或 R.id.nav_items_group_extra 并将所需的 XML 添加到您的示例中,可能会更清楚 IS onNavigationItemSelected(final MenuItem menuItem) 默认方法??我应该在哪里做这个代码? 什么是 NAV_ITEMS_MAIN??【参考方案8】:

我想在第一项上方和最后一项之后设置分隔线。使用@Nilesh 解决方案,我必须添加虚拟菜单项并将启用设置为 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_
    android:layout_
    android:layout_gravity="start"
    android:fitsSystemWindows="true"
    app:menu="@menu/empty_menu">

    <!--CUSTOM CONTENT-->
    <RelativeLayout
        android:layout_
        android:layout_>

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

        <!--CUSTOM MENU-->
        <LinearLayout
            android:layout_
            android:layout_
            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:
          android: />
</shape>

还有菜单

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

编辑:

你可以使用 TextView 代替 Buttons,它可以模仿原始菜单项的外观:

 <TextView
     android:layout_
     android:layout_
     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>

【讨论】:

谢谢,将自定义视图作为菜单项显然是最方便的方式 我使用这个解决方案也是因为它让我更容易设置项目的自定义字体并更改分隔线颜色【参考方案9】:

应该向 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 的常量【参考方案10】:

调用需要 API 级别 28:

随便用

 menu?.setGroupDividerEnabled(true)

在 onCreateOptionsMenu 函数中

例子:

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)


    

【讨论】:

【参考方案11】:

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 可以解决问题

【讨论】:

【参考方案12】:

如果你想动态地添加分隔符,你可以像这样添加一个空的子菜单:

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

这将添加一个分隔符。

使用menu.getItem(int index)时一定要传入正确的索引

【讨论】:

【参考方案13】:

如果您确实想要装饰性分隔符但由于“可检查行为”问题而不想创建多个组,除了之前的答案之外 - 您可以为所有组分配相同的组 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>

【讨论】:

【参考方案14】:

如果您选择的答案不适合您,您可能想尝试将其添加到 onCreateOptionsMenu 并提供唯一的组 ID:

if (Build.VERSION.SDK_INT >= 28) 
    menu.setGroupDividerEnabled(true)

【讨论】:

以上是关于如何在新的 NavigationView 中创建一个简单的分隔线?的主要内容,如果未能解决你的问题,请参考以下文章

无法在新的CCW独立安装中创建Clojure项目或命名空间

在新窗口 C++ 中创建线程

如何在新的 Google Play 控制台版本中添加消耗品应用内产品

如何在 Xcode 中创建一个新的 C++ 项目?

如何在 Python 中创建一组集合?

如何在 Spark 中创建一组 ngram?