一、 DrawerLayout
DrawerLayout官網(wǎng)教程
DrawerLayout官網(wǎng)API
在很多應(yīng)用中都會有抽屜式導航欄,鑒于此,谷歌就提供了DrawerLayout來實現(xiàn)這個功能.

DrawerLayout在v4包中,使用時需要導入v4包,使用eclipse創(chuàng)建項目會自動導入v4包,使用studio創(chuàng)建項目時會自動添加v7依賴,v7是兼容v4的,所以直接用就是了......
1、 DrawerLayout的簡單使用
DrawerLayout的使用非常簡單,只要遵循幾個規(guī)則就行了
布局文件:
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="主頁面" />
</RelativeLayout>
<ListView
android:id="@+id/list_view"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="@android:color/holo_blue_dark"
android:choiceMode="singleChoice"
android:divider="@android:color/transparent"
android:dividerHeight="0dp"
android:scrollbars="none" />
</android.support.v4.widget.DrawerLayout>
直接使用DrawerLayout作為根標簽,然后DrawerLayout根據(jù)android:layout_gravity屬性判斷哪個是側(cè)滑面板,使用start/end或者left/right來表明是抽屜式導航欄是左邊的還是右邊的,沒有android:layout_gravity屬性的就是主頁面視圖了.
ok,簡單的側(cè)滑效果完成了,就是這么簡單,來看一下效果圖:

是不是很簡單,官網(wǎng)介紹了使用DrawerLayout的幾條規(guī)范:
1、DrawerLayout最好聲明為根標簽
2、在DrawerLayout中,主頁面視圖(上面的 TextView那一部分,當然,這個內(nèi)容是你自己決定的,不一定要是TextView)必須是第一個子視圖
3、主頁面視圖設(shè)置為匹配父視圖的寬度和高度, 因為在抽屜式導航欄處于隱藏狀態(tài)時, 它代表整個 UI
4、抽屜式導航欄視圖 必須使用 android:layout_gravity屬性指定。
如果要支持“從右到左”(RTL) 語言,請使用 "start"(而非"left")指定該值(這樣當布局為 RTL 時,抽屜式導航欄會顯示在右側(cè))。
PS:RTL就是從右到左(Right To Left)的布局,我們在手機上/設(shè)置/開發(fā)者選項中有一個強制使用從右到左的布局方向,可以打開試一試效果.
雖然我們國內(nèi)app一般都是從左到右,但我們還是聽谷歌的建議比較好,使用start/end而非left/right.
5、抽屜式導航欄視圖以 dp 為單位指定其寬度, 且高度與父視圖相匹配。抽屜式導航欄的寬度不應(yīng)超過 320dp,從而用戶始終可以看到部分主內(nèi)容。
2、 抽屜的數(shù)據(jù)填充
抽屜其實只是一個普通的View,這里我放的是ListView,看起來就像菜單,當然,你完全可以只放一個ImageView、TextView等等。這和Activity的菜單不一樣,Activity的菜單只需要在資源文件中定義好,就能按照固定的形式顯示出來。而DrawerLayout的側(cè)邊菜單顯示成什么樣完全是取決于你自己,同樣點擊菜單之后的邏輯也完全由你自己去寫。
接下來給菜單填充數(shù)據(jù)
布局文件
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="主頁面" />
<Button
android:id="@+id/bt_open"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="打開" />
</RelativeLayout>
<ListView
android:id="@+id/list_view"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="@android:color/holo_blue_dark"
android:choiceMode="singleChoice"
android:divider="@android:color/transparent"
android:dividerHeight="0dp"
android:scrollbars="none" />
</android.support.v4.widget.DrawerLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity {
private List<String> mDatas;
private DrawerLayout mDrawerLayout;
private ListView mListView;
private TextView tvMain;
private Button btOpen;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initData();
initView();
mListView.setAdapter(new ArrayAdapter<>(MainActivity.this,android.R.layout.simple_list_item_1,mDatas));
/**
* 點擊菜單條目更改主界面TextView內(nèi)容,同時關(guān)閉菜單
* 關(guān)閉菜單使用DrawerLayout.closeDrawer()方法,傳入要關(guān)閉的菜單View或者菜單的方向都可以
*/
mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
tvMain.setText(mDatas.get(position));
mDrawerLayout.closeDrawer(mListView);
// mDrawerLayout.closeDrawer(GravityCompat.START);
}
});
/**
* 打開菜單使用DrawerLayout.openDrawer()方法,傳入要關(guān)閉的菜單View或者菜單的方向都可以
*/
btOpen.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mDrawerLayout.openDrawer(GravityCompat.START);
// mDrawerLayout.openDrawer(mListView);
}
});
}
private void initView() {
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mListView = (ListView) findViewById(R.id.list_view);
tvMain = (TextView) findViewById(R.id.tv_main);
btOpen = (Button) findViewById(R.id.bt_open);
}
private void initData() {
mDatas = new ArrayList<>();
for (int i = 'A'; i < 'Z'; i++) {
mDatas.add("" + (char) i);
}
}
}
效果圖

實際開發(fā)中這里的主頁面視圖一般用FrameLayout代替,點擊菜單條目,動態(tài)為FrameLayout添加內(nèi)容.
ok,簡單的介紹了DrawerLayout的使用,接下來來看一下我們今天的主角
二、NavigationView
1、NavigationView是什么
NavigationView就是菜單View,也就是上面我們使用的ListView那一部分。
那么,有了DrawerLayout之后為什么還會出現(xiàn)一個NavigationView,看下面這張圖:

這種效果的菜單用ListView或者RecyclerView也能實現(xiàn),不過總要花點時間吧,但是用NavigationView之后簡直分分鐘搞定.
2、NavigationView的使用
(1)簡單使用
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="主頁面" />
</RelativeLayout>
<android.support.design.widget.NavigationView
android:id="@+id/navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/header"
app:menu="@menu/main">
</android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>
NavigationView就是菜單面板,其中最重要的兩條屬性就是:
1、這就是菜單面板的頭布局,也就是剛才頭像,昵稱那一欄,引用了一個布局文件
app:headerLayout="@layout/header"
header.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="150dp"
android:background="@color/colorPrimaryDark"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:layout_width="144dp"
android:layout_height="90dp"
android:layout_marginTop="10dp"
android:background="@mipmap/icon" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center"
android:text="隨風飄揚的smile"
android:textColor="@android:color/white"
android:textSize="15sp" />
</LinearLayout>
2、這就是菜單面板的內(nèi)容部分,也就是會員特權(quán)、XX錢包...那一部分,定義在res/menu/main.xml中
app:menu="@menu/main"
main.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/item_1"
android:icon="@mipmap/a"
android:title="會員特權(quán)" />
<item
android:id="@+id/item_2"
android:icon="@mipmap/b"
android:title="XX錢包" />
<item
android:id="@+id/item_3"
android:icon="@mipmap/c"
android:title="個性裝扮" />
<item
android:id="@+id/item_4"
android:icon="@mipmap/d"
android:title="我的收藏" />
<item
android:id="@+id/item_5"
android:icon="@mipmap/e"
android:title="我的相冊" />
<item
android:id="@+id/item_6"
android:icon="@mipmap/f"
android:title="設(shè)置" />
</menu>
header和item部分內(nèi)容都是根據(jù)實際需要來設(shè)置的.
(2)效果圖:

效果有點不一樣,沒有了分隔線,而且圖片都是灰灰的。
(3)添加分隔線:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:id="@+id/group1">
<item
android:id="@+id/item_1"
android:icon="@mipmap/a"
android:title="會員特權(quán)" />
</group>
<group android:id="@+id/group2">
<item
android:id="@+id/item_2"
android:icon="@mipmap/b"
android:title="XX錢包" />
</group>
<group android:id="@+id/group3">
<item
android:id="@+id/item_3"
android:icon="@mipmap/c"
android:title="個性裝扮" />
</group>
<group android:id="@+id/group4">
<item
android:id="@+id/item_4"
android:icon="@mipmap/d"
android:title="我的收藏" />
</group>
<group android:id="@+id/group5">
<item
android:id="@+id/item_5"
android:icon="@mipmap/e"
android:title="我的相冊" />
</group>
<group android:id="@+id/group6">
<item
android:id="@+id/item_6"
android:icon="@mipmap/f"
android:title="設(shè)置" />
</group>
</menu>
在菜單條目文件中給item分組,就可以添加分隔線了。
再來看效果圖:

ok!
(4)解決圖片變灰問題:
方式1:你可以為NavigationView設(shè)置下面這條屬性,不過那樣item圖片只能是統(tǒng)一的顏色
app:itemIconTint=""
方式2:Activity中代碼設(shè)置,這樣能讓圖片恢復(fù)原樣了
mNavigationView = (NavigationView) findViewById(R.id.navigation_view);
mNavigationView.setItemIconTintList(null);
ok,現(xiàn)在效果圖和剛開始那張圖完全一樣了。
(5)item繼續(xù)添加分組:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:id="@+id/group1">
<item
android:id="@+id/item_1"
android:icon="@mipmap/a"
android:title="會員特權(quán)" />
</group>
<group android:id="@+id/group2">
<item
android:id="@+id/item_2"
android:icon="@mipmap/b"
android:title="XX錢包" />
</group>
<group android:id="@+id/group3">
<item
android:id="@+id/item_3"
android:icon="@mipmap/c"
android:title="個性裝扮" />
</group>
<group android:id="@+id/group4">
<item
android:id="@+id/item_4"
android:icon="@mipmap/d"
android:title="我的收藏" />
</group>
<group android:id="@+id/group5">
<item
android:id="@+id/item_5"
android:icon="@mipmap/e"
android:title="我的相冊" />
</group>
<group android:id="@+id/group6">
<item
android:id="@+id/item_6"
android:icon="@mipmap/f"
android:title="設(shè)置" />
</group>
<group android:id="@+id/group7">
<item
android:id="@+id/item_7"
android:icon="@mipmap/f"
android:title="其它" >
<menu>
<item
android:id="@+id/item_8"
android:icon="@mipmap/f"
android:title="分享" />
<item
android:id="@+id/item_9"
android:icon="@mipmap/f"
android:title="隱私" />
</menu>
</item>
</group>
</menu>
效果圖:

當item過多會出現(xiàn)滾動條,如果要隱藏滾動條,給NavigationView設(shè)置android:scrollbars="none"是不管用的,因為這個滾動條不是NavigationView的,而是菜單的·.
可以在Activity中找到菜單View,然后取消滾動條
NavigationMenuView menuView = (NavigationMenuView) mNavigationView.getChildAt(0);
menuView.setVerticalScrollBarEnabled(false);
3、NavigationView其它屬性
給菜單item部分添加背景
app:itemBackground=" "
給菜單item文字設(shè)置顏色
app:itemTextColor=" "
更多文字特效可以通過下面這條屬性設(shè)置:
app:itemTextAppearance=" "
4、菜單item的一些屬性
設(shè)定一組菜單項可以選中幾個item,none、single、all三個值
<group android:id="@+id/group1" android:checkableBehavior="single">
菜單項 item 是否被選中,如果要默認選中一個菜單 item 則設(shè)為true
<item android:checked="true" />
5、NavigationView點擊事件
(1)頭部點擊事件
headerView = mNavigationView.getHeaderView(0);
headerView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this,"headerView",Toast.LENGTH_SHORT).show();
}
});
找到headerView ,然后設(shè)置點擊事件即可
(2)頭部控件點擊事件
通過headerView.findViewById()找到要點擊的控件,然后設(shè)置點擊事件即可
ivIcon = (ImageView) headerView.findViewById(R.id.icon);
tvName = (TextView) headerView.findViewById(R.id.name);
ivIcon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this,"icon",Toast.LENGTH_SHORT).show();
}
});
tvName.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this,"name",Toast.LENGTH_SHORT).show();
}
});
(3)item點擊事件
通過NavigationView.setNavigationItemSelectedListener()設(shè)置監(jiān)聽即可
mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()){
case R.id.item_1:
//do something
break;
case R.id.item_2:
//do something
break;
//......
}
return false;
}
});
(4)隱藏菜單某部分item
有時候可能會有些奇葩的需求,要求我們隱藏一些菜單item,滿足一定條件才會顯示出來.
MenuItem item = mNavigationView.getMenu().findItem(R.id.item_1);//找到要隱藏的item
item.setVisible(false);//false即隱藏,true即顯示
三、 完整代碼
Activity布局文件:
<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/tv_main"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="主頁面" />
</RelativeLayout>
<android.support.design.widget.NavigationView
android:id="@+id/navigation_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="left"
app:itemTextColor="@color/colorPrimaryDark"
app:headerLayout="@layout/header"
app:menu="@menu/main">
</android.support.design.widget.NavigationView>
</android.support.v4.widget.DrawerLayout>
header布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="150dp"
android:background="@color/colorPrimaryDark"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/icon"
android:layout_width="144dp"
android:layout_height="90dp"
android:layout_marginTop="10dp"
android:background="@mipmap/icon" />
<TextView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center"
android:text="隨風飄揚的smile"
android:textColor="@android:color/white"
android:textSize="15sp" />
</LinearLayout>
菜單文件
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:id="@+id/group1">
<item
android:id="@+id/item_1"
android:icon="@mipmap/a"
android:title="會員特權(quán)" />
</group>
<group android:id="@+id/group2">
<item
android:id="@+id/item_2"
android:icon="@mipmap/b"
android:title="XX錢包" />
</group>
<group android:id="@+id/group3">
<item
android:id="@+id/item_3"
android:icon="@mipmap/c"
android:title="個性裝扮" />
</group>
<group android:id="@+id/group4">
<item
android:id="@+id/item_4"
android:icon="@mipmap/d"
android:title="我的收藏" />
</group>
<group android:id="@+id/group5">
<item
android:id="@+id/item_5"
android:icon="@mipmap/e"
android:title="我的相冊" />
</group>
<group android:id="@+id/group6">
<item
android:id="@+id/item_6"
android:icon="@mipmap/f"
android:title="設(shè)置" />
</group>
<group android:id="@+id/group7">
<item
android:id="@+id/item_7"
android:icon="@mipmap/f"
android:title="其它">
<menu>
<item
android:id="@+id/item_8"
android:icon="@mipmap/f"
android:title="分享" />
<item
android:id="@+id/item_9"
android:icon="@mipmap/f"
android:title="隱私" />
</menu>
</item>
</group>
</menu>
MainActivity.java
public class MainActivity extends AppCompatActivity {
private DrawerLayout mDrawerLayout;
private TextView tvMain;
private NavigationView mNavigationView;
private View headerView;
private ImageView ivIcon;
private TextView tvName;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
tvMain = (TextView) findViewById(R.id.tv_main);
mNavigationView = (NavigationView) findViewById(R.id.navigation_view);
mNavigationView.setItemIconTintList(null);//讓菜單item圖片正常
// 隱藏菜單item
// MenuItem item = mNavigationView.getMenu().findItem(R.id.item_1);
// item.setVisible(false);
/**
* 隱藏滾動條
*/
NavigationMenuView menuView = (NavigationMenuView) mNavigationView.getChildAt(0);
menuView.setVerticalScrollBarEnabled(false);
/**
* header點擊事件
*/
headerView = mNavigationView.getHeaderView(0);
headerView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this,"headerView",Toast.LENGTH_SHORT).show();
}
});
/**
* headerView中組件點擊事件
*/
ivIcon = (ImageView) headerView.findViewById(R.id.icon);
tvName = (TextView) headerView.findViewById(R.id.name);
ivIcon.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this,"icon",Toast.LENGTH_SHORT).show();
}
});
tvName.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Toast.makeText(MainActivity.this,"name",Toast.LENGTH_SHORT).show();
}
});
/**
* 菜單item點擊事件
*/
mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case R.id.item_1:
//do something
break;
case R.id.item_2:
//do something
break;
//......
}
return false;
}
});
}
}
效果圖
