Android 笔记 popupMenu 显示图标

popupMenu

多数时候,我们需要设置popupMenu,这样可以在点击的时候显示菜单,可操作性比系统菜单,toolbar菜单强,所以用处更加广泛。

popupMenu的菜单实际上和toolbar上的是一样的,设置内容的方法类似,都可以从xml文件创建,或者动态添加项目。但是有一点,就是没有图标。
toolbar上的菜单可以设置图标,但是只有选项直接显示在toolbar上的时候才有图标(显示图标的时候就不显示文字),选项溢出在菜单里面的时候,会显示文字,尔没有图标。
补充一,在后面)

popupMenu干脆就没有图标,只有文字。虽然可以用popupMenu.getMenu()获得menu的对象,然后设置图标menu.add("name").setIcon(...),但是根本不显示。

据说早期android可以设置图标并且显示的,有一个可以设置的public方法设置是否显示图标。
后来4.0版本以后,干脆屏蔽了这个方法,变成了private的,就是说普通方式无法显示图标了。

不知道他们怎么想的。

设置显示图标

网上查到一个方法,可以用“反射”机制来改变这个class,然后设置这个隐藏起来的方法,用来显示图标。
这个反射,就是说可以获得一个class类,然后修改这个类的内容,然后再运行。
看起来很危险容易被恶意利用,但是有些时候会很有用。

private void setIconEnable(Menu menu, boolean enable)  
    {  
        try   
        {  
            Class<?> clazz = Class.forName("com.android.internal.view.menu.MenuBuilder");  
            Method m = clazz.getDeclaredMethod("setOptionalIconsVisible", boolean.class);  
            m.setAccessible(true);  
            //传入参数
            m.invoke(menu, enable);  

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

(以上方法是我从网上抄来的)
这个方法传入两个参数,第一个就是menu对象,第二个是boolean,是否启用
整个方法就是改变了setOptionalIconsVisible()方法,这本来是一个隐藏起来的方法,这里利用反射机制调用之。
这个方法是MenuBuilder类里面的,不是Menu里面的,这个MenuBuilder也是非公开的

这样就可以显示popupMenu的图标了

其他代替的办法

除了上面这种比较特别扽办法意外,可以自建一个类继承PopupMenu,但是操作起来跟上面类似。

或者干脆,用其他的widget代替popupMenu。
比如PopupWindow,自定义一个View,然后添加一个ImageView一个textView,可以做到类似的Menu效果
有一个listPopupWindow,定义了一个特殊的PopupWindow,看起来就跟Menu差不多了,使用起来更方便。
具体看官方API文档
PopupWindow

补充一

发现一个可以显示toolbar溢出菜单的图标的方法
设置toolbar菜单项的时候,如果设置showAsAction为 never,或者ifroom的时候,会放在溢出菜单里面,就是最后面的竖着3个点构成的按钮,里面的菜单是没有图标只有文字的(可以用前面反射的方法让它出现图标)。但是如果设置成多层级菜单,就可以显示图标,在模拟器5.0系统上证实可以。

<item android:id="@+id/action_more"
        android:icon="@drawable/ic_action_more"
        android:showAsAction="always">
        <menu>
            <item android:id="@+id/action_search"
                android:title="搜索"
                android:icon="@drawable/ic_action_search"
                android:showAsAction="ifRoom">
            </item>
            <item android:id="@+id/action_more_one"
                android:title="动作一"
                android:icon="@drawable/ic_action_search"
                android:showAsAction="never">

            </item>
            <item android:id="@+id/action_more_two"
                android:title="动作二"
                android:icon="@drawable/ic_action_search"
                android:showAsAction="never">
            </item>
        </menu>

    </item>
    <item android:id="@+id/action_share"
        android:title="分享"
        android:icon="@drawable/ic_action_share"
        android:showAsAction="always">
    </item>

这样设置,最外层有两个图标,点击第一个,就会显示新的层级菜单,这个菜单是有图标的。
这个第二层的菜单称之为subMenu,官方文档说subMenu不支持图标,但是这里显示了图标,不知道为什么。
于是我找到一种方法,就是用subMenu显示图标。
方法onCreateOptionsMenu在创建视图的时候调用一次,用来初始化菜单
onPrepareOptionsMenu在每次菜单显示的时候调用,初始化的时候也调用一次。在点击溢出菜单(就是最右边的竖直三个点图标)的时候也调用一次。

所以,在合适的方法里可以添加subMenu,然后定义这个subMenu的menuItem,

//创建submenu,并且添加到menu里面。
SubMenu subMenu = menu.addSubMenu(groupId, id,order,label);
//把submenu的show_as_action设置为_always,这样会总是显示在界面上
//另外还可以像普通item一样设置图标 setIcon()
subMenu.getItem().setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
//添加menuItem
subMenu.add("Yes").setIcon(R.drawable.ic_action_more);

如此一来就添加了一个像popupMenu一样的二级菜单,并且有图标

另外

有一个ActionProvider类,可以用来创建子菜单
继承之,然后覆盖里面的一个方法

@Override
        public void onPrepareSubMenu(SubMenu subMenu) {
            super.onPrepareSubMenu(subMenu);

            subMenu.clear();

            subMenu.add("menu 1");
            subMenu.add("menu 2");
            subMenu.add("menu 3");
        }

在menuItem里面设置这个actionProvider
menu.add("provider").setActionProvider(new MyActionProvider(thisActivity)).setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);

我觉得没有上一种方法好,但是有效果。

  • 7
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值