Material Design 控件知識(shí)梳理(1) - Android Design Support Library 是什么
Material Design 控件知識(shí)梳理(2) - AppBarLayout & CollapsingToolbarLayout
Material Design 控件知識(shí)梳理(3) - BottomSheet && BottomSheetDialog && BottomSheetDialogFragment
Material Design 控件知識(shí)梳理(4) - FloatingActionButton
Material Design 控件知識(shí)梳理(5) - DrawerLayout && NavigationView
Material Design 控件知識(shí)梳理(6) - Snackbar
Material Design 控件知識(shí)梳理(7) - BottomNavigationBar
Material Design 控件知識(shí)梳理(8) - TabLayout
Material Design 控件知識(shí)梳理(9) - TextInputLayout
一、概述
今天妻枕,我們來(lái)介紹兩個(gè)和側(cè)滑菜單有關(guān)的MD
控件:
-
DrawerLayout
:實(shí)現(xiàn)側(cè)滑菜單的基礎(chǔ)。 -
NavigationView
:作為側(cè)滑菜單布局的一種實(shí)現(xiàn)方式博杖。
二、DrawerLayout
2.1 基本原理
當(dāng)我們需要使用到側(cè)滑菜單時(shí)筷登,可以通過(guò)DrawerLayout
來(lái)實(shí)現(xiàn)剃根,DrawerLayout
、側(cè)滑菜單布局前方、普通布局這三者的關(guān)系為:
layout_gravity
決定了將哪個(gè)菜單作為側(cè)滑布局狈醉,DrawerLayout
會(huì)根據(jù)是否聲明了layout_gravity
屬性,把它內(nèi)部的直接子View
分成兩類(lèi):
- 對(duì)于沒(méi)有聲明
layout_gravity
的布局惠险,那么它會(huì)將它們當(dāng)作普通布局苗傅,并按照FrameLayout
的方式來(lái)排列它們。 - 對(duì)于聲明了
layout_gravity="start"
或者layout_gravity="left"
的布局班巩,在普通情況下會(huì)將它們隱藏起來(lái)渣慕,當(dāng)從屏幕的最左側(cè)往右移動(dòng)手指時(shí),這個(gè)布局會(huì)漸漸展現(xiàn)出來(lái)抱慌,對(duì)于DrawerLayout
的所有子View
來(lái)說(shuō)摇庙,只允許有一個(gè)子View
的該屬性為start/left
,這就是我們的側(cè)滑布局遥缕。 -
layout_gravity="end/right"
和上面類(lèi)似卫袒,只不過(guò)它的調(diào)出是從屏幕的右側(cè)向左側(cè)移動(dòng)。
2.2 簡(jiǎn)單事例
下面是一個(gè)使用DrawerLayout
的最簡(jiǎn)單的例子:
<android.support.v4.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".DrawerLayoutActivity">
<!-- 普通布局 -->
<FrameLayout
android:id="@+id/fl_content"
android:background="@android:color/holo_orange_dark"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:text="我是內(nèi)容布局"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</FrameLayout>
<!-- 側(cè)滑布局 -->
<include layout="@layout/layout_drawer_normal"/>
</android.support.v4.widget.DrawerLayout>
layout_drawer_normal
就是側(cè)滑菜單单匣,我們將它的layout_gravity
定義為start
夕凝,按照前面的分析,它應(yīng)當(dāng)位于屏幕的左側(cè):
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_gravity="start"
android:layout_width="200dp"
android:background="@android:color/holo_green_dark"
android:layout_height="match_parent">
<TextView
android:text="我是側(cè)滑布局"
android:layout_gravity="center"
android:textColor="@android:color/white"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
下面是最終的效果:
2.3 監(jiān)聽(tīng)DrawerLayout
的狀態(tài)變化
如果我們希望監(jiān)聽(tīng)DrawerLayout
狀態(tài)的變化户秤,那么可以通過(guò)下面這個(gè)方法:
private Toolbar mToolbar;
private ActionBarDrawerToggle mActionBarDrawerToggle;
private DrawerLayout mDrawerLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_drawer_layout_simple);
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerLayout.addDrawerListener(new DrawerLayout.DrawerListener() {
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
Log.d("mDrawerLayout", "onDrawerSlide, slideOffset=" + slideOffset);
}
@Override
public void onDrawerOpened(View drawerView) {
Log.d("mDrawerLayout", "onDrawerOpened");
}
@Override
public void onDrawerClosed(View drawerView) {
Log.d("mDrawerLayout", "onDrawerClosed");
}
@Override
public void onDrawerStateChanged(int newState) {
Log.d("mDrawerLayout", "onDrawerStateChanged, state=" + newState);
}
});
}
其中opened
和closed
方法都很好理解码秉,就是對(duì)應(yīng)展開(kāi)和收起,而onDrawerSlide
方法中的slideOffset
鸡号,則對(duì)應(yīng)于DrawerLayout
展開(kāi)的偏移值转砖,全部展開(kāi)時(shí)為1
,全部收起時(shí)為0
鲸伴,onDrawerStateChanged
對(duì)應(yīng)于所處的狀態(tài):STATE_IDLE/STATE_DRAGGING/STATE_SETTLING
府蔗。
三、DrawerLayout
和Toolbar
結(jié)合使用
3.1 Toolbar
的NavigationIcon
跟隨DrawerLayout
變化
下面汞窗,我們看一下把DrawerLayout
和Toolbar
相結(jié)合姓赤,做出下面的效果,讓Toolbar
的navigationIcon
跟隨著DrawerLayout
變化:
當(dāng)拖動(dòng)側(cè)邊欄的時(shí)候仲吏,
Toolbar
的按鈕會(huì)跟隨著進(jìn)行狀態(tài)的變化不铆,我們也可以通過(guò)點(diǎn)擊Toolbar
的按鈕來(lái)展開(kāi)和收起側(cè)邊欄蝌焚,首先看我們的布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Toolbar -->
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:background="@android:color/holo_green_dark"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"/>
<android.support.v4.widget.DrawerLayout
android:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- 普通布局 -->
<FrameLayout
android:id="@+id/fl_content"
android:background="@android:color/holo_orange_dark"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:text="我是內(nèi)容布局"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</FrameLayout>
<!-- 側(cè)滑布局 -->
<include layout="@layout/layout_drawer_normal"/>
</android.support.v4.widget.DrawerLayout>
</LinearLayout>
在Activity
中,我們需要將Toolbar
和DrawerLayout
關(guān)聯(lián)起來(lái):
public class DrawerLayoutActivity extends AppCompatActivity {
private Toolbar mToolbar;
private ActionBarDrawerToggle mActionBarDrawerToggle;
private DrawerLayout mDrawerLayout;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_drawer_layout_under_toolbar);
initView();
}
private void initView() {
mToolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(mToolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true); //1.決定顯示.
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mActionBarDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, mToolbar, R.string.drawer_open, R.string.drawer_close); //2.傳入Toolbar可以點(diǎn)擊.
mDrawerLayout.addDrawerListener(mActionBarDrawerToggle); //3.監(jiān)聽(tīng)變化.
}
@Override
protected void onPostCreate(@Nullable Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
//4.同步狀態(tài)
mActionBarDrawerToggle.syncState();
}
}
這里需要做的有四步工作:
- 將
Toolbar
作為ActionBar
誓斥,并調(diào)用Toolbar
的setDisplayHomeAsUpEnabled
只洒,這樣最左邊的Icon
才可以顯示。 - 實(shí)例化
ActionBarDrawerToggle
劳坑,并傳入Toolbar
和DrawerLayout
毕谴。 - 通過(guò)
DrawerLayout
的addDrawerListener
方法,讓DrawerLayout
的狀態(tài)能夠回調(diào)到ActionBarDrawerToggle
泡垃。 - 在
onPostCreate
中析珊,調(diào)用ActionBarDrawerToggle
的syncState
方法羡鸥。
3.2 DrawerLayout
覆蓋Toolbar
在上面的實(shí)現(xiàn)方式中蔑穴,側(cè)滑菜單位于Toolbar
的下方,如果我們希望它覆蓋Toolbar
惧浴,那么可以像下面這樣布局:
<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">
<!-- 普通布局 -->
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:background="@android:color/holo_green_dark"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"/>
<FrameLayout
android:id="@+id/fl_content"
android:background="@android:color/holo_orange_dark"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:text="我是內(nèi)容布局"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</FrameLayout>
</LinearLayout>
<!-- 側(cè)滑布局 -->
<include layout="@layout/layout_drawer_normal"/>
</android.support.v4.widget.DrawerLayout>
最終的效果為:
3.3 DrawerLayout
和Toolbar
延伸到狀態(tài)欄上方
如果我們希望側(cè)滑菜單的區(qū)域能夠延伸到狀態(tài)欄存和,那么可以進(jìn)行以下三步的修改:
- 第一步:修改
Activity
的style
,讓狀態(tài)欄透明衷旅,并修改狀態(tài)欄的顏色:
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorAccent">@color/colorAccent</item>
<!-- 修改狀態(tài)欄顏色 -->
<item name="colorPrimaryDark">@android:color/holo_green_dark</item>
<!-- 狀態(tài)欄透明 -->
<item name="android:windowTranslucentStatus">true</item>
</style>
</resources>
- 第二步:給
Activity
根布局設(shè)置android:fitsSystemWindows="true"
屬性
<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"
android:fitsSystemWindows="true">
<!-- 普通布局 -->
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:background="@android:color/holo_green_dark"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"/>
<FrameLayout
android:id="@+id/fl_content"
android:background="@android:color/holo_orange_dark"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:text="我是內(nèi)容布局"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</FrameLayout>
</LinearLayout>
<!-- 側(cè)滑布局 -->
<include layout="@layout/layout_drawer_normal"/>
</android.support.v4.widget.DrawerLayout>
- 第三步:給側(cè)滑布局設(shè)置
android:fitsSystemWindows="true"
屬性
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_gravity="start"
android:layout_width="200dp"
android:background="@android:color/holo_green_dark"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<TextView
android:text="我是側(cè)滑布局"
android:layout_gravity="center"
android:textColor="@android:color/white"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
通過(guò)以上三步捐腿,就可以達(dá)到沉浸式狀態(tài)欄的效果:
四、NavigationView
4.1 Navigation
屬性
在使用DrawerLayout
的時(shí)候柿顶,我們可以隨意定義側(cè)滑菜單的布局茄袖,NavigationView
其實(shí)就是Google
推薦的側(cè)滑布局應(yīng)該有的樣子,它的效果類(lèi)似于下面這樣:
我們先來(lái)看一個(gè)使用
Navigation
的簡(jiǎn)單例子:
<android.support.design.widget.NavigationView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="300dp"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/layout_drawer_navigation_header"
app:menu="@menu/menu_navigation"
app:itemIconTint="@android:color/white"
app:itemBackground="@android:color/holo_green_dark"
app:itemTextColor="@android:color/black">
</android.support.design.widget.NavigationView>
上面app
各屬性對(duì)應(yīng)到下圖中就是這樣:
可以看到嘁锯,
Navigation
分為兩個(gè)部分:頭部和列表宪祥。
- 頭部是
app:headerLayout
所指定的布局:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ImageView
android:src="@drawable/ic_bg"
android:scaleType="centerCrop"
android:layout_width="match_parent"
android:layout_height="200dp"/>
</LinearLayout>
- 列表通過(guò)
app:menu
所指定:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/favorite"
android:icon="@mipmap/ic_launcher"
android:title="收藏"/>
<item
android:id="@+id/wallet"
android:icon="@mipmap/ic_launcher"
android:title="錢(qián)包"/>
<item
android:id="@+id/photo"
android:icon="@mipmap/ic_launcher"
android:title="相冊(cè)"/>
<item
android:id="@+id/file"
android:icon="@mipmap/ic_launcher"
android:title="文件"/>
</menu>
menu
當(dāng)中的每個(gè)item
就對(duì)應(yīng)于列表當(dāng)中的一項(xiàng),而item
的icon
和title
則分別對(duì)應(yīng)列表項(xiàng)的圖標(biāo)和文字家乘,如果希望對(duì)item
進(jìn)行分組蝗羊,那么可以采用group
的方式來(lái)組織menu
:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:id="@+id/group1">
<item
android:id="@+id/favorite"
android:icon="@mipmap/ic_launcher"
android:title="group1 - item1"/>
<item
android:id="@+id/wallet"
android:icon="@mipmap/ic_launcher"
android:title="group1 - item2"/>
</group>
<group android:id="@+id/group2">
<item
android:id="@+id/photo"
android:icon="@mipmap/ic_launcher"
android:title="group2 - item1"/>
<item
android:id="@+id/file"
android:icon="@mipmap/ic_launcher"
android:title="group2 - item2"/>
</group>
</menu>
不同組之間就會(huì)被分割線(xiàn)隔開(kāi):
如果想要給某個(gè)分組添加標(biāo)題,那么可以采用
subMenu
的方式:
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:id="@+id/group1">
<item
android:id="@+id/item1"
android:icon="@mipmap/ic_launcher"
android:title="group1 - item1"/>
<item
android:id="@+id/item2"
android:icon="@mipmap/ic_launcher"
android:title="group1 - item2"/>
</group>
<group android:id="@+id/group2">
<item
android:id="@+id/item3"
android:icon="@mipmap/ic_launcher"
android:title="group2 - item1"/>
<item
android:id="@+id/item4"
android:icon="@mipmap/ic_launcher"
android:title="group2 - item2"/>
</group>
<item
android:id="@+id/item5"
android:title="group3">
<menu>
<item
android:id="@+id/item6"
android:icon="@mipmap/ic_launcher"
android:title="group3 - item1"/>
<item
android:id="@+id/item7"
android:icon="@mipmap/ic_launcher"
android:title="group3 - item2"/>
</menu>
</item>
</menu>
4.2 Navigation
點(diǎn)擊監(jiān)聽(tīng)
4.2.1 列表點(diǎn)擊監(jiān)聽(tīng)
如果希望處理Navigation
中列表的監(jiān)聽(tīng)耀找,那么可以使用現(xiàn)成的接口业崖,根據(jù)item
的id
來(lái)判斷是點(diǎn)擊的是列表中的哪一項(xiàng)。
mNavigationView = (NavigationView) findViewById(R.id.navigation);
mNavigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
Log.d("onSelected", "id=" + item.getItemId());
return true;
}
});
4.2.2 頭部點(diǎn)擊監(jiān)聽(tīng)
NavigationView
并沒(méi)有提供頭部點(diǎn)擊的監(jiān)聽(tīng)回調(diào)复罐,因此雄家,我們只能夠通過(guò)findViewById
的方法找到對(duì)應(yīng)的View
胀滚,對(duì)其設(shè)置監(jiān)聽(tīng)乱投,下面是整個(gè)headerLayout
在NavigationView
中的層次:
五、參考文獻(xiàn)
Android 5.0 之 NavigationView 的使用
更多文章剑刑,歡迎訪(fǎng)問(wèn)我的 Android 知識(shí)梳理系列:
- Android 知識(shí)梳理目錄:http://www.reibang.com/p/fd82d18994ce
- 個(gè)人主頁(yè):http://lizejun.cn
- 個(gè)人知識(shí)總結(jié)目錄:http://lizejun.cn/categories/