參考:
2.NavigationView更改菜單icon和title顏色變化效果
轉了第一篇
NavigationView 的引入讓 Android 側邊欄實現起來相當方便,最近公司項目中也使用這個新的控件完成了側邊欄的改版。在使用過程中遇到一些坑,寫篇博文記錄一下。
本文分為兩大主要部分,第一部分是基本使用,第二部分是各種使用小細節(坑),如果你對其使用已經熟悉了,可以跳過第一部分。
基本使用
1. NavigationView 在 design 庫中,添加依賴(最新的是 23.2.0);
compile 'com.android.support:design:23.1.1'
2. 然后在 DrawerLayout 布局中添加 NavigationView ;
<?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.DrawerLayout android:id="@+id/drawer_layout" xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:id="@+id/main" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="@color/colorPrimary" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/> ...... </LinearLayout> </FrameLayout> <android.support.design.widget.NavigationView android:id="@+id/navigation" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" app:headerLayout="@layout/nav_header" app:menu="@menu/activity_main_drawer"/> </android.support.v4.widget.DrawerLayout>
其中需要注意給 NavigationView 設置 android:layout_gravity="start" 屬性。
3.然后注意到 NavigationView 其實是分兩個部分的,一個是頭部,一個是下面的菜單列表部分,如下圖所示:

app:headerLayout="@layout/nav_header" 屬性添加,nav_header 的布局如下:
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="192dp" android:theme="@style/ThemeOverlay.AppCompat.Dark"> <ImageView android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/nav_header_bg" android:scaleType="centerCrop"/> <ImageView android:layout_width="96dp" android:layout_height="96dp" android:layout_gravity="bottom" android:layout_marginBottom="36dp" android:padding="8dp" android:src="@drawable/ic_avatar"/> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:padding="16dp" android:text="Jaeger" android:textAppearance="@style/TextAppearance.AppCompat.Body1"/> </FrameLayout>
下面的菜單列表部分是一個 menu 文件,通過 app:menu="@menu/activity_main_drawer"屬性添加。
activity_main_drawer.xml 文件在 menu 文件夾下,內容為:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <group android:checkableBehavior="single"> <item android:id="@+id/nav_camera" android:icon="@drawable/ic_menu_camera" android:title="Import"/> <item android:id="@+id/nav_gallery" android:icon="@drawable/ic_menu_gallery" android:title="Gallery"/> <item android:id="@+id/nav_slideshow" android:icon="@drawable/ic_menu_slideshow" android:title="Slideshow"/> <item android:id="@+id/nav_manage" android:icon="@drawable/ic_menu_manage" android:title="Tools"/> </group> <item android:title="Communicate"> <menu> <item android:id="@+id/nav_share" android:icon="@drawable/ic_menu_share" android:title="Share"/> <item android:id="@+id/nav_send" android:icon="@drawable/ic_menu_send" android:title="Send"/> </menu> </item> </menu>
4. 菜單列表的點擊事件
菜單列表的點擊事件設置代碼如下:
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(MenuItem item) { switch (item.getItemId()){ case R.id.nav_personal_info: // do something break; ... } return false; } });
至此,NavigationView 的基本使用就差不多搞定了,效果就是前面圖片顯示的效果。接下來是各種填坑環節。??
使用小細節(和坑)
1. 獲得頭部(header)內控件
ImageView,你可以在 activity 中直接調用 findViewById() 方法來獲得。但是在 Support Library 23.1.0 版本之后,這個不再適用,在我使用的 Support Library 23.1.1 版本中,可以直接調用 getHeaderView()方法先得到 Header,然后在通過header來獲得頭部內的控件。
View headerView = navigationView.getHeaderView(0);
ImageView ivAvatar = (ImageView) headerView.findViewById(R.id.nav_avatar);
然后就可以進行各種愉快的頭像設置,用戶名設置了~
關於這個問題,如果你用的不是23.1.1版本的話,你可以看 stackoverflow 上的討論 NavigationView get/find header layout,針對其他版本也有解決方法說明。
2. 菜單列表中的圖標不顯示原始顏色
當設計師為每一項的圖標都設置了不同的顏色時,你將切好的彩色圖標文件放進去,運行后發現全變成灰色了。此時可以通過 app:itemIconTint="@color/blue" 為圖標統一設置顏色,前后效果如下:

然而這還不是我們需要的效果,我們需要的是彩色的圖標,而不是統一的圖標顏色。
解決方法是調用 NavigationView 的 setItemIconTintList(ColorStateList tint) 方法,傳入 null 參數:
navigationView.setItemIconTintList(null);
最終效果如下:

3. 添加分割線
如上面的截圖所示,菜單列表分成了兩個部分,中間用一個分割線隔開。解決方法是在 menu 文件中分成多個 group ,且為每個 group 設置 id ,如下:
<?xml version="1.0" encoding="utf-8"?> <menu xmlns:android="http://schemas.android.com/apk/res/android"> <group android:id="@+id/first_group" android:checkableBehavior="none"> <item android:id="@+id/nav_personal_info" android:icon="@drawable/nav_personal_info" android:title="@string/personal_info_setting"/> ... <item android:id="@+id/nav_system_setting" android:icon="@drawable/nav_setting" android:title="@string/system_setting"/> </group> <group android:id="@+id/second_group"> <item android:id="@+id/nav_score" android:icon="@drawable/nav_score" android:title="@string/score"/> <item android:id="@+id/nav_feedback" android:icon="@drawable/nav_feedback" android:title="@string/feedback"/> </group> </menu>
4. 隱藏某個菜單列表項
公司項目會根據你是否是管理員,來控制某個菜單列表項的顯示和隱藏,因此就出現了這個問題。
原以為比較麻煩,后來搜了下,也比較簡單地解決了,直接上代碼:
MenuItem menuItem = navigationView.getMenu().findItem(R.id.some_menu_item); menuItem.setVisible(false); // true 為顯示,false 為隱藏
這個問題也就這么解決了。??
5. 使用 NavigationView 時透明狀態欄的處理
這個問題可以看我上一篇文章來解決 Android App 沉浸式狀態欄解決方案,里面會講到如何處理抽屜視圖的透明狀態欄的實現。
寫在最后感謝原作者的分享。我在此僅作學習記錄之用~
