- 今天就記錄一下昨天寫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;
}
});