-
今天就记录一下昨天写bug的时候使用Popupmenu的时候遇到的一些问题吧
尝试使用Popupmenu,避免不必要的坑。我贴的代码都是我最后的代码。记录自己看一下。后来参考的人就看看步骤就行。先看看我最后的效果图:
壹、Popupmenu的基本使用,定义和获取对应的menu菜单项。
- 首先我们来定义一个menu.xml来放我们的菜单项目。
menu xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/changeIO"
android:orderInCategory="120"
android:icon="@drawable/changeio"
android:title="切换进出方向" />
<item
android:id="@+id/workstart"
android:orderInCategory="120"
android:icon="@drawable/work"
android:title="出工" />
<item
android:id="@+id/workfinish"
android:orderInCategory="120"
android:icon="@drawable/finishwork"
android:title="收工" />
<item
android:id="@+id/rollcall"
android:orderInCategory="120"
android:icon="@drawable/rollcall"
android:title="点名" />
<item
android:id="@+id/areactrl"
android:orderInCategory="120"
android:icon="@drawable/areactrl"
android:title="零星流动" />
</menu>
- 然后我们直接把菜单按钮设置监听,在里面定义popupmenu。获取表单信息即可。下面两行代码放进去就行。功能就是点击图标按钮即可弹出菜单。
private View.OnClickListener ioSwitcherListener = v -> {
PopupMenu popupMenu = new PopupMenu(FaceActivity.this, v); //FaceActivity是当前使用类
popupMenu.getMenuInflater().inflate(R.menu.face_menu, popupMenu.getMenu());
popupMenu.show(); //关键,弹出菜单显示
}
-
我们来看看具体效果图吧。这是我之前啥效果都没加的时候。只列了两个选项。可以看到没有分割线。白白的很丑。我们后面爱继续优化吧。
贰、Popupmenu设置字体风格和弹出定位。添加分割线。
- 由于风格单调,我们需要把它弄得好看一点。做安卓的应该都做过按钮。和按钮这些一样。我们看可以单独为他定制一个style。在value文件夹里面新建itemstyle.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="mainStyle" parent="Theme.AppCompat"> <!--主风格、mainStyle-->
<item name="android:dropDownListViewStyle">@style/popmenuDivier</item>
<item name="android:textAppearanceSmallPopupMenu">@style/popmenuText</item>
<item name="android:textAppearanceLargePopupMenu">@style/popmenuText</item>
</style>
<!--popmenu的字体颜色-->
<style name="popmenuText">
<item name="android:textColor">@color/white</item>
<item name="android:textSize">20sp</item>
<item name="android:gravity">center</item>
</style>
<!--popMenu分割线的颜色-->
<style name="popmenuDivier">
<item name="android:divider">@color/md_blue_600</item>
<item name="android:dividerHeight">2sp</item>
</style>
</resources>
- 关于这个style文件,我具体还没摸清哪些风格对应的是啥。主风格里面嵌套其他风格。引用继承的关系。主风格parent网上的都是写的AppThem。我用这个无法编译。我开始把它删了。所有都可以用。这个parent其实可有可无。但是后面添加icon就出问题了。所以我才加了Theme.AppCompat。但是加了这个就无法使用popupmenu的背景、定位的自定义风格。目前没找到问题所在。希望后来的大佬知道的指点一下。因为我的也可以将就着用。我就没添加背景和定位!关于定位和背景需要的。大家可以参考一下这篇博客
-
最后在对应使用的activity配置,例如我的是FaceActivity,把这一条添加到对应的activity就行了。
-
我们来看看具体效果图,添加了分割线,字体风格和Theme.AppCompat默认背景风格。到这一步差不多就是下面的风格。奇怪的是没有定位它默认跑到一个合理的位置上了,免去了定位的烦恼。
-
由于之前我没有继承parent。定位和背景也可以正常使用看看你我的先后对比图。这是没有设置定位和背景
-
这是设置了背景和定位的。这些在主风格都没继承parent的。可以看到就整齐美观了许多。
叁、为Popupmenu添加icon:两种方法:反射、子菜单模式
a、利用反射强制展示icon。这里面有点坑。
- 虽然定位,背景都设置了,但是还是觉得很丑。这时候我就尝试着为每个表单添加icon。也就是本文开始的那种效果。我搜了许多,都是用的反射显示。我也用的反射实现的。我们只需要在刚才定义popupmenu的后面加一段代码即可实现。
//使用反射,强制显示菜单图标
try {
Field field = popupMenu.getClass().getDeclaredField("mPopup");
field.setAccessible(true);
MenuPopupHelper mHelper = (MenuPopupHelper) field.get(popupMenu);
mHelper.setForceShowIcon(true);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}finally {
popupMenu.show();
}
- 说到这里我就有话要说了。由于之前项目比较老了。这个MenuPopupHelper死都不出来。android.support.v7.widget报找不到。检查发现我导的包和别人用的不一样。我又尝试添加了一下依赖。
结果解决了么,并没有!又报错了。编译失败,说我v4和v7冲突了。反正就是这个问题。最后检查发现在另一个build.gradle里面还有个v4.我把它注释了就好了。貌似v4和v7差不多。但是有重合的部分。网上说把冲突的jar删了即可。
b、子菜单模式,不用反射,直接显示。
- 利用表嵌套,当然具体还看需求而定。我还没尝试如何怎么调整显示为我想要的效果。但至少提供了一种思路。这是我在谷歌上找到的。百度上的都是利用那个反射强制显示的。这个就直接第一步的代码啥都不用加。
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/main"
android:orderInCategory="120"
android:title="主菜单" >
<menu>
<item
android:id="@+id/changeIO"
android:orderInCategory="120"
android:icon="@drawable/changeio"
android:title="切换进出方向" />
<item
android:id="@+id/workstart"
android:orderInCategory="120"
android:icon="@drawable/work"
android:title="出工" />
<item
android:id="@+id/workfinish"
android:orderInCategory="120"
android:icon="@drawable/finishwork"
android:title="收工" />
<item
android:id="@+id/rollcall"
android:orderInCategory="120"
android:icon="@drawable/rollcall"
android:title="点名" />
<item
android:id="@+id/open"
android:orderInCategory="120"
android:icon="@drawable/areactrl"
android:title="零星流动" />
</menu>
</item>
</menu>
肆、动态管理Popupmenu表单项。隐藏菜单中指定的选项。
- 这个问题不知道是我没找到还是啥,各大网站没找到对应的解决方案。最后在谷歌找到的。一种是比较愚蠢的,添加所需的menu项.可以参照着我的menu.xml看。但是这个蠢就蠢在我费劲千辛万苦添上去的icon又不在了。变成了这个样子。
popupMenu.getMenu().add(Menu.NONE, R.id.rollcall, Menu.NONE, "点名详情");
popupMenu.getMenu().add(Menu.NONE, R.id.workfinish, Menu.NONE, "收工");
popupMenu.getMenu().add(Menu.NONE, R.id.changeIO, Menu.NONE, "切换进出方向");
- 另外就是比较nice的解决方案了。原理就是把他的显示参数设置为不可见。答案来自谷歌。手动笑哭!!我把其中两个隐藏了。这样我们就可以根据后端传过来的标识显示对应的menu项。最后效果:看着就会很nice !我特么把这生生搞成了进化史!哈哈
popupMenu.getMenu().findItem(R.id.rollcall).setVisible(false);
popupMenu.getMenu().findItem(R.id.workfinish).setVisible(false);
伍、为Popupmenu菜单设置监听。
- 最难的我们都经历了,剩下来这个就比较简单了。直接Switch就行了。哇,写累了直接上代码吧!手动滑稽!直接加在popupmenu.show后面就行
popupMenu.setOnMenuItemClickListener(
new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
switch (item.getItemId()) {
case R.id.rollcall:
Comm.loger.output("切换点名。");
break;
case R.id.workstart:
Comm.loger.output("切换出工。");
break;
//此处省略一万字
default:
// 隐藏该对话框
Toast.makeText(FaceActivity.this,
"您单击了【" + item.getTitle() + "】菜单项"
, Toast.LENGTH_SHORT).show();
}
return true;
}
});