美文网首页
巧用PopupMenu实现NavigationView的二级子菜

巧用PopupMenu实现NavigationView的二级子菜

作者: 缺牙青蛙 | 来源:发表于2018-02-26 02:31 被阅读0次

    个人原创,转载请注明出处: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代码如下:

    <menu xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
        ...
            <item
                android:id="@+id/nav_xxx"
                android:icon="@drawable/nav_xxx"
                android:title="@string/donate"
                app:actionLayout="@layout/anchor"/> <!--插入的具体布局-->
        ...
    </menu>
    

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

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="wrap_content"
        android:layout_height="1dp" />
    

    可见只是一个空的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的二级子菜

          本文链接:https://www.haomeiwen.com/subject/kordxftx.html