個(gè)人原創(chuàng),轉(zhuǎn)載請注明出處:http://www.reibang.com/p/1dcb9eff6052
來簡書的第一篇文章炸裆,想了想就以這個(gè)作為開頭了^^
概述
寫自己的app時(shí)屿讽,發(fā)現(xiàn)NavigationView的默認(rèn)菜單功能不支持類似OptionMenu那樣點(diǎn)擊后彈出二級子菜單的功能粘衬,思考了下想用PopupMenu來實(shí)現(xiàn)青抛,現(xiàn)將遇到的坑和具體實(shí)現(xiàn)記錄如下科盛。
PopupMenu基本用法
這里推薦使用support-v7包下的PopupMenu兄世,兼容更多版本且功能更豐富:
PopupMenu popupMenu = new PopupMenu(context, anchorView);
popupMenu.inflate(R.menu.xxx);
popupMenu.show();
popupMenu.setOnMenuItemClickListener(...)甜孤;
NavigationView下彈出PopupMenu
上面構(gòu)造函數(shù)的第二個(gè)參數(shù)anchorView表示popupMenu彈出時(shí)確定其位置的錨點(diǎn)老速。于是自然想到用NavigationView的menuitem來實(shí)現(xiàn):
Menu navMenu = navigationView.getMenu();
MenuItem menuItem = navMenu.findItem(R.id.xxx);
anchorView = menuItem.getActionView();
完事了粥喜?還早著呢!編譯后發(fā)現(xiàn)報(bào)錯(cuò):
IllegalStateException: MenuPopupHelper cannot be used without an anchor
提示沒有錨點(diǎn)橘券。咦额湘?我們不是傳入了menuItem.getActionView()作為錨點(diǎn)么?
查詢MenuItem的getActionView()方法源碼后發(fā)現(xiàn)該方法返回的不是一個(gè)具體的控件或布局的view旁舰,所以導(dǎo)致popupMenu無法確定具體的錨點(diǎn)锋华。
在網(wǎng)上搜索了一下解決方法,發(fā)現(xiàn)可以通過給NavigationView的menuItem傳入一個(gè)具體的布局來實(shí)現(xiàn)錨點(diǎn)的定位箭窜,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" />
可見只是一個(gè)空的LinearLayout,僅用來定位磺樱。這里將height設(shè)為1主要是為了防止layout擠占menu的空間導(dǎo)致UI變形纳猫。完成后再編譯運(yùn)行婆咸,效果如下:
功能正常實(shí)現(xiàn)了^^
進(jìn)階:給PopupMenu加上icon
最早的PopupMenu也是可以像NavigationView里的menu一樣給設(shè)置icon的,但后來google為了明確區(qū)分PopupMenu和PopupWindow的使用芜辕,將相應(yīng)的方法給精簡掉了尚骄。但別忘了我們使用的是support-v7包的PopupMenu,這里依然可以利用MenuPopupHelper來實(shí)現(xiàn)物遇。
MenuPopupHelper popupHelper = new MenuPopupHelper(context,(MenuBuilder) menu,view);
popupHelper.setForceShowIcon(true);
其中第二個(gè)參數(shù)需要傳入當(dāng)前menu并轉(zhuǎn)化為MenuBuilder類型乖仇,而PopupMenu類型本身不能轉(zhuǎn)化憾儒,可用popupMenu.getMenu()來實(shí)現(xiàn)询兴。第三個(gè)參數(shù)就是上文已經(jīng)說過的錨點(diǎn)。然后調(diào)用popupHelper的setForceShowIcon(true)方法就可以強(qiáng)制item顯示icon了起趾。
這里還有兩個(gè)小坑:
Android Studio 3.0以上版本調(diào)用MenuPopupHelper的以上兩行代碼時(shí)編譯器會報(bào)“xxx can only be called from within the same library group...”诗舰。這應(yīng)該是個(gè)bug,解決方法很簡單训裆,在調(diào)用以上兩個(gè)方法的方法體前面加上@SuppressLint("RestrictedApi")的注釋眶根,如:
@SuppressLint("RestrictedApi")
private void showPopupMenu(){
...
}
填完上面的坑后,運(yùn)行边琉,發(fā)現(xiàn)還是不能顯示icon属百?這是因?yàn)槲覀儗opupMenu的自定義是在popupHelper里進(jìn)行的,所以最后不能用popupMenu.show()变姨,而是要調(diào)用
popupHelper.show();
好了大功告成族扰,看看最終效果吧:
參考
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