NavigationView是一种标准的应用导航菜单,菜单栏的内容可以来自菜单栏资源文件。
NavigationView最典型的应用场景是放到DrawerLayout里使用。
API:https://developer.android.com/reference/android/support/design/widget/NavigationView.html
1. build.gradle里面添加 compile 'com.android.support:design:24.0.0',版本号需要跟API版本号相同;
apply plugin: 'com.android.application'
android {
compileSdkVersion 24
buildToolsVersion "24.0.0"
defaultConfig {
applicationId "com.media.customplayer"
minSdkVersion 18
targetSdkVersion 24
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
productFlavors {
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:24.0.0'
compile 'com.android.support:design:24.0.0'
}
2. 布局配置文件添加指向res-auto的域名 xmlns:app="http://schemas.android.com/apk/res-auto"
<?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/palyer_drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:context=".PlayerActivity" >
3. res目录下添加menu目录,在menu下添加菜单栏资源文件
menu api: http://developer.android.com/guide/topics/resources/menu-resource.html
<?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/navi_all" android:checked="true" android:icon="@mipmap/ic_allmusic_black_24dp" android:title="@string/drawer_allmusic_title" /> <item android:id="@+id/navi_playlists" android:icon="@mipmap/ic_playlist_music_black_24dp" android:title="@string/drawer_playlists_title" /> </group> </menu>
4. DrawerLayout下添加NavigationView(至此导航栏可以使用了)
<?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/palyer_drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:context=".PlayerActivity" > <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="200dp" android:layout_marginTop="200dp" android:text="这是主区域"/> </RelativeLayout> <android.support.design.widget.NavigationView android:id="@+id/navi_view" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" app:menu="@menu/drawer" /> </android.support.v4.widget.DrawerLayout>
5. app:headerLayout接收一个导航菜单栏顶部的布局(可选)
<?xml version="1.0" encoding="utf-8"?> <android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/palyer_drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:context=".PlayerActivity" > <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="200dp" android:layout_marginTop="200dp" android:text="这是主区域"/> </RelativeLayout> <android.support.design.widget.NavigationView android:id="@+id/navi_view" android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="start" app:headerLayout="@layout/nav_header" app:menu="@menu/drawer" /> </android.support.v4.widget.DrawerLayout>
nav_header.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="192dp" android:background="?attr/colorPrimaryDark" android:padding="16dp" app:theme="@style/ThemeOverlay.AppCompat.Dark" android:gravity="bottom"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="导航栏Header" android:textAppearance="@style/TextAppearance.AppCompat.Body1" /> </LinearLayout>
6. menu嵌套
menu支持分组和子标题,但是子标题不支持icon
<?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/navi_all" android:checked="true" android:icon="@mipmap/ic_allmusic_black_24dp" android:title="@string/drawer_allmusic_title" /> <item android:id="@+id/navi_playlists" android:icon="@mipmap/ic_playlist_music_black_24dp" android:title="@string/drawer_playlists_title" /> <item android:id="@+id/navi_sub_header" android:icon="@mipmap/ic_by_genre" android:title="@string/drawer_sub_navi_title"> <menu> <item android:id="@+id/navi_sub_item_1" android:icon="@mipmap/ic_allmusic_black_24dp" android:title="@string/drawer_sub_playlist_title" /> <item android:id="@+id/navi_sub_item_2" android:icon="@mipmap/ic_allmusic_black_24dp" android:title="@string/drawer_sub_playlist_title" /> </menu> </item> </group> </menu>
经过测试,子分组可以放到group里面,可以放到外面
<?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/navi_all" android:checked="true" android:icon="@mipmap/ic_allmusic_black_24dp" android:title="@string/drawer_allmusic_title" /> <item android:id="@+id/navi_playlists" android:icon="@mipmap/ic_playlist_music_black_24dp" android:title="@string/drawer_playlists_title" /> <item android:id="@+id/navi_sub_header" android:icon="@mipmap/ic_by_genre" android:title="@string/drawer_sub_navi_title"> <menu> <item android:id="@+id/navi_sub_item_1" android:icon="@mipmap/ic_allmusic_black_24dp" android:title="@string/drawer_sub_playlist_title" /> <item android:id="@+id/navi_sub_item_2" android:icon="@mipmap/ic_allmusic_black_24dp" android:title="@string/drawer_sub_playlist_title" /> </menu> </item> </group> <item android:id="@+id/navi_sub_header_bottom" android:icon="@mipmap/ic_by_genre" android:title="@string/drawer_sub_navi_title"> <menu> <item android:id="@+id/navi_sub_item_bottom_1" android:icon="@mipmap/ic_allmusic_black_24dp" android:title="@string/drawer_sub_playlist_title" /> <item android:id="@+id/navi_sub_item_bottom_2" android:icon="@mipmap/ic_allmusic_black_24dp" android:title="@string/drawer_sub_playlist_title" /> </menu> </item> </menu>
7. 导航菜单项被点击时的回掉:setNavigationItemSelectedListener(OnNavigationItemSelectedListener)
package com.media.customplayer; import android.support.design.widget.NavigationView; import android.support.design.widget.NavigationView.OnNavigationItemSelectedListener; import android.support.v4.view.GravityCompat; import android.support.v4.widget.DrawerLayout; import android.support.v4.widget.DrawerLayout.DrawerListener; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import android.view.MenuItem; import android.view.View; public class PlayerActivity extends AppCompatActivity { private final String TAG = "PlayerActivity"; private DrawerLayout mPlayerDrawer; private NavigationView mNaviView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_player); mPlayerDrawer = (DrawerLayout) findViewById(R.id.palyer_drawer_layout); mPlayerDrawer.addDrawerListener(drawerListener); mNaviView = (NavigationView) findViewById(R.id.navi_view); mNaviView.setNavigationItemSelectedListener(naviItemSelectedListener); } private DrawerListener drawerListener = new DrawerLayout.DrawerListener() { @Override public void onDrawerSlide(View drawerView, float slideOffset) { Log.v(TAG, "onDrawerSlide: slideOffset = " + slideOffset); } @Override public void onDrawerOpened(View drawerView) { Log.v(TAG, "onDrawerOpened"); } @Override public void onDrawerClosed(View drawerView) { Log.v(TAG, "onDrawerClosed"); } @Override public void onDrawerStateChanged(int newState) { Log.v(TAG, "onDrawerStateChanged: newState = " + newState); } }; private OnNavigationItemSelectedListener naviItemSelectedListener = new OnNavigationItemSelectedListener() { @Override public boolean onNavigationItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.navi_all: Log.v(TAG, "播放所有音乐"); break; case R.id.navi_playlists: Log.v(TAG, "播放音乐列表"); break; default: Log.v(TAG, "点击按钮: " + item.getItemId()); } item.setChecked(true); mPlayerDrawer.closeDrawer(GravityCompat.START, true); return true; } }; }
但是问题来了,分组的菜单项虽然可以触发此事件,但是子分组的菜单项此时都变成多选了
经过测试发现,子分组menu下先嵌套group(
<item>
<menu>
<group android:checkableBehavior="single">
<item />
<item />
</group>
</menu>
</item>
),再嵌套item即可解决。
<?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/navi_all" android:checked="true" android:icon="@mipmap/ic_allmusic_black_24dp" android:title="@string/drawer_allmusic_title" /> <item android:id="@+id/navi_playlists" android:icon="@mipmap/ic_playlist_music_black_24dp" android:title="@string/drawer_playlists_title" /> <item android:id="@+id/navi_sub_header" android:icon="@mipmap/ic_by_genre" android:title="@string/drawer_sub_navi_title"> <menu> <group android:checkableBehavior="single"> <item android:id="@+id/navi_sub_item_1" android:icon="@mipmap/ic_allmusic_black_24dp" android:title="@string/drawer_sub_playlist_title" /> <item android:id="@+id/navi_sub_item_2" android:icon="@mipmap/ic_allmusic_black_24dp" android:title="@string/drawer_sub_playlist_title" /> </group> </menu> </item> </group> <item android:id="@+id/navi_sub_header_bottom" android:icon="@mipmap/ic_by_genre" android:title="@string/drawer_sub_navi_title"> <menu> <group android:checkableBehavior="single"> <item android:id="@+id/navi_sub_item_bottom_1" android:icon="@mipmap/ic_allmusic_black_24dp" android:title="@string/drawer_sub_playlist_title" /> <item android:id="@+id/navi_sub_item_bottom_2" android:icon="@mipmap/ic_allmusic_black_24dp" android:title="@string/drawer_sub_playlist_title" /> </group> </menu> </item> </menu>
还需要注意的时,选中的菜单项,还是可以触发selected事件的。