Android开发: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>
如图所示:
但是设计不喜欢这个线条啊,很粗啊,颜色不好看啊!好吧改!不过在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();
- }
- }
效果图如下:
再来个更直观的图: