给 NavigationView 的Menu的分割线 设置高度和颜色

最近遇到了一个问题,是给DrawerLayout的NavigationView的导航添加分割线,项目中的左侧导航栏之前的实现是用系统Menu的方式来实现的,需求要给导航添加分割线,并且自定义颜色和高度,查看文档虽然能通过给menu通过group加id的方式添加分割线 ,代码如下:

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

    <group
        android:id="@+id/group1"
        android:checkableBehavior="single">
        <item
            android:id="@+id/nav_camera"
            android:icon="@drawable/ic_menu_camera"
            android:title="Import" />
        <item
            android:id="@+id/nav_gallery"
            android:icon="@drawable/ic_menu_gallery"
            android:title="Gallery" />
    </group>
    <group
        android:id="@+id/group2"
        android:checkableBehavior="single">
        <item
            android:id="@+id/nav_slideshow"
            android:icon="@drawable/ic_menu_slideshow"
            android:title="Slideshow" />
        <item
            android:id="@+id/nav_manage"
            android:icon="@drawable/ic_menu_manage"
            android:title="Tools" />
    </group>
    <group android:id="@+id/group3">
        <item
            android:id="@+id/nav_share"
            android:icon="@drawable/ic_menu_share"
            android:title="Share" />
        <item
            android:id="@+id/nav_send"
            android:icon="@drawable/ic_menu_send"
            android:title="Send" />
    </group>

</menu>

显示如下图:

Paste_Image.png

但是设计不喜欢这个线条啊,很粗啊,颜色不好看啊!好吧改!不过在NavigationView上没有找到可以订制的属性!然后查看NavigationView的源代码,发现 左侧栏的布局是通过NavigationMenuPresenter这个类来实现的,通过查看NavigationMenuPresenter的代码发现了 design_navigation_item_separator.xml 这个布局:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
             android:layout_width="match_parent"
             android:layout_height="wrap_content">

    <View android:layout_width="match_parent"
          android:layout_height="1dp"
          android:background="?android:attr/listDivider"/>

</FrameLayout>

发现颜色是可以通过在主题里通过listDivider属性来配置,但是高度固定1dp了,View 没有ID说明就没有考虑这个高度,怎么改?
看看NavigationMenuPresenter的具体实现吧,左侧栏整个布局是通过RecyclerView 来实现的,通过不同的 View 的 TYPE 类型来加载不同的布局!那么是不是可以从 RecyclerView 的 addOnChildAttachStateChangeListener 方法入手?
实践出真知!
我们可以先通过反射得到RecyclerView:

Field fieldByPressenter = navigationView.getClass().getDeclaredField("mPresenter");
            fieldByPressenter.setAccessible(true);
            NavigationMenuPresenter menuPresenter = (NavigationMenuPresenter) fieldByPressenter.get(navigationView);
            Field fieldByMenuView = menuPresenter.getClass().getDeclaredField("mMenuView");
            fieldByMenuView.setAccessible(true);
            final NavigationMenuView mMenuView = (NavigationMenuView) fieldByMenuView.get(menuPresenter);

mMenuView就是RecyclerView,剩下的是给其注册addOnChildAttachStateChangeListener监听,每加载一个view 就获取它的ViewHolder,通过判断ViewHolder是否是SeparatorViewHolder(是分割线的独有ViewHolder)的实例,来确定分割线View,然后想怎么操作就怎么操作!完整代码如下:

 public static void setNavigationMenuLineStyle(NavigationView navigationView, @ColorInt final int color, final int height) {
        try {
            Field fieldByPressenter = navigationView.getClass().getDeclaredField("mPresenter");
            fieldByPressenter.setAccessible(true);
            NavigationMenuPresenter menuPresenter = (NavigationMenuPresenter) fieldByPressenter.get(navigationView);
            Field fieldByMenuView = menuPresenter.getClass().getDeclaredField("mMenuView");
            fieldByMenuView.setAccessible(true);
            final NavigationMenuView mMenuView = (NavigationMenuView) fieldByMenuView.get(menuPresenter);
            mMenuView.addOnChildAttachStateChangeListener(new RecyclerView.OnChildAttachStateChangeListener() {
                @Override
                public void onChildViewAttachedToWindow(View view) {
                    RecyclerView.ViewHolder viewHolder = mMenuView.getChildViewHolder(view);
                    if (viewHolder != null && "SeparatorViewHolder".equals(viewHolder.getClass().getSimpleName()) && viewHolder.itemView != null) {
                        if (viewHolder.itemView instanceof FrameLayout) {
                            FrameLayout frameLayout = (FrameLayout) viewHolder.itemView;
                            View line = frameLayout.getChildAt(0);
                            line.setBackgroundColor(color);
                            line.getLayoutParams().height = height;
                            line.setLayoutParams(line.getLayoutParams());
                        }
                    }
                }

                @Override
                public void onChildViewDetachedFromWindow(View view) {

                }
            });
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }

效果图如下:

Paste_Image.png

再来个更直观的图:

Paste_Image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 173,678评论 25 708
  • 最近做了一个Android UI相关开源项目库汇总,里面集合了OpenDigg 上的优质的Android开源项目库...
    OpenDigg阅读 17,319评论 6 222
  • (一)深夜,田地里不时传来青蛙地呱呱声,陈浩打着手电筒,背着一个蛇皮袋,走在田路中,前方不远处就是小甜姐家的菜地了...
    方糖镜阅读 1,774评论 1 6
  • 生活之美,处处皆是。
    瑲珩阅读 334评论 1 0
  • 1. 上级是面对很多个下级的组织者。他代表公司雇用你,是在购买你的能力和时间,以节省自己的精力和时间。从这个意义上...
    姜戈一阅读 909评论 0 0