巧用PopupMenu实现NavigationView的二级子菜单

个人原创,转载请注明出处:https://www.jianshu.com/p/1dcb9eff6052

来的第一篇文章,想了想就以这个作为开头了^^

概述

写自己的app时,发现NavigationView的默认菜单功能不支持类似OptionMenu那样点击后弹出二级子菜单的功能,思考了下想用PopupMenu来实现,现将遇到的坑和具体实现记录如下。

PopupMenu基本用法

这里推荐使用support-v7包下的PopupMenu,兼容更多版本且功能更丰富:

PopupMenu popupMenu = new PopupMenu(context, anchorView);
popupMenu.inflate(R.menu.xxx);
popupMenu.show();
popupMenu.setOnMenuItemClickListener(...);

NavigationView下弹出PopupMenu

上面构造函数的第二个参数anchorView表示popupMenu弹出时确定其位置的锚点。于是自然想到用NavigationView的menuitem来实现:

Menu navMenu = navigationView.getMenu();
MenuItem menuItem = navMenu.findItem(R.id.xxx);
anchorView = menuItem.getActionView();

完事了?还早着呢!编译后发现报错:

IllegalStateException: MenuPopupHelper cannot be used without an anchor

提示没有锚点。咦?我们不是传入了menuItem.getActionView()作为锚点么?
查询MenuItem的getActionView()方法源码后发现该方法返回的不是一个具体的控件或布局的view,所以导致popupMenu无法确定具体的锚点。
在网上搜索了一下解决方法,发现可以通过给NavigationView的menuItem传入一个具体的布局来实现锚点的定位,menu.xml代码如下:


    ...
         
    ...

注意命名空间,anchor.xml代码如下:



可见只是一个空的LinearLayout,仅用来定位。这里将height设为1主要是为了防止layout挤占menu的空间导致UI变形。完成后再编译运行,效果如下:


popupmenu1.gif

功能正常实现了^^

进阶:给PopupMenu加上icon

最早的PopupMenu也是可以像NavigationView里的menu一样给设置icon的,但后来google为了明确区分PopupMenu和PopupWindow的使用,将相应的方法给精简掉了。但别忘了我们使用的是support-v7包的PopupMenu,这里依然可以利用MenuPopupHelper来实现。

MenuPopupHelper popupHelper = new MenuPopupHelper(context,(MenuBuilder) menu,view);
popupHelper.setForceShowIcon(true);

其中第二个参数需要传入当前menu并转化为MenuBuilder类型,而PopupMenu类型本身不能转化,可用popupMenu.getMenu()来实现。第三个参数就是上文已经说过的锚点。然后调用popupHelper的setForceShowIcon(true)方法就可以强制item显示icon了。
这里还有两个小坑:
Android Studio 3.0以上版本调用MenuPopupHelper的以上两行代码时编译器会报“xxx can only be called from within the same library group...”。这应该是个bug,解决方法很简单,在调用以上两个方法的方法体前面加上@SuppressLint("RestrictedApi")的注释,如:

@SuppressLint("RestrictedApi")
private void showPopupMenu(){
            ...
}

填完上面的坑后,运行,发现还是不能显示icon?这是因为我们对popupMenu的自定义是在popupHelper里进行的,所以最后不能用popupMenu.show(),而是要调用

popupHelper.show();

好了大功告成,看看最终效果吧:


popupmenu2.gif

参考

https://stackoverflow.com/questions/41238545/anchoring-a-popupmenu-to-navigationview-menu-items
https://stackoverflow.com/questions/15454995/popupmenu-with-icons#
https://stackoverflow.com/questions/41150995/appcompatactivity-oncreate-can-only-be-called-from-within-the-same-library-group

你可能感兴趣的:(巧用PopupMenu实现NavigationView的二级子菜单)