今天,咱們來介紹兩個和側滑菜單有關的MD
控件:android
DrawerLayout
:實現側滑菜單的基礎。NavigationView
:做爲側滑菜單佈局的一種實現方式。DrawerLayout
當咱們須要使用到側滑菜單時,能夠經過DrawerLayout
來實現,DrawerLayout
、側滑菜單佈局、普通佈局這三者的關係爲: bash
layout_gravity
決定了將哪一個菜單做爲側滑佈局,
DrawerLayout
會根據是否聲明瞭
layout_gravity
屬性,把它內部的直接子
View
分紅兩類:
layout_gravity
的佈局,那麼它會將它們看成普通佈局,並按照FrameLayout
的方式來排列它們。layout_gravity="start"
或者layout_gravity="left"
的佈局,在普通狀況下會將它們隱藏起來,當從屏幕的最左側往右移動手指時,這個佈局會漸漸展示出來,對於DrawerLayout
的全部子View
來講,只容許有一個子View
的該屬性爲start/left
,這就是咱們的側滑佈局。layout_gravity="end/right"
和上面相似,只不過它的調出是從屏幕的右側向左側移動。下面是一個使用DrawerLayout
的最簡單的例子:app
<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="我是內容佈局"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</FrameLayout>
<!-- 側滑佈局 -->
<include layout="@layout/layout_drawer_normal"/>
</android.support.v4.widget.DrawerLayout>
複製代碼
layout_drawer_normal
就是側滑菜單,咱們將它的layout_gravity
定義爲start
,按照前面的分析,它應當位於屏幕的左側:ide
<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="我是側滑佈局"
android:layout_gravity="center"
android:textColor="@android:color/white"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
複製代碼
下面是最終的效果: 佈局
DrawerLayout
的狀態變化若是咱們但願監聽DrawerLayout
狀態的變化,那麼能夠經過下面這個方法:ui
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
方法都很好理解,就是對應展開和收起,而onDrawerSlide
方法中的slideOffset
,則對應於DrawerLayout
展開的偏移值,所有展開時爲1
,所有收起時爲0
,onDrawerStateChanged
對應於所處的狀態:STATE_IDLE/STATE_DRAGGING/STATE_SETTLING
。this
DrawerLayout
和Toolbar
結合使用Toolbar
的NavigationIcon
跟隨DrawerLayout
變化下面,咱們看一下把DrawerLayout
和Toolbar
相結合,作出下面的效果,讓Toolbar
的navigationIcon
跟隨着DrawerLayout
變化: spa
Toolbar
的按鈕會跟隨着進行狀態的變化,咱們也能夠經過點擊
Toolbar
的按鈕來展開和收起側邊欄,首先看咱們的佈局
<?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="我是內容佈局"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</FrameLayout>
<!-- 側滑佈局 -->
<include layout="@layout/layout_drawer_normal"/>
</android.support.v4.widget.DrawerLayout>
</LinearLayout>
複製代碼
在Activity
中,咱們須要將Toolbar
和DrawerLayout
關聯起來:.net
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能夠點擊.
mDrawerLayout.addDrawerListener(mActionBarDrawerToggle); //3.監聽變化.
}
@Override
protected void onPostCreate(@Nullable Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
//4.同步狀態
mActionBarDrawerToggle.syncState();
}
}
複製代碼
這裏須要作的有四步工做:3d
Toolbar
做爲ActionBar
,並調用Toolbar
的setDisplayHomeAsUpEnabled
,這樣最左邊的Icon
才能夠顯示。ActionBarDrawerToggle
,並傳入Toolbar
和DrawerLayout
。DrawerLayout
的addDrawerListener
方法,讓DrawerLayout
的狀態可以回調到ActionBarDrawerToggle
。onPostCreate
中,調用ActionBarDrawerToggle
的syncState
方法。DrawerLayout
覆蓋Toolbar
在上面的實現方式中,側滑菜單位於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="我是內容佈局"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</FrameLayout>
</LinearLayout>
<!-- 側滑佈局 -->
<include layout="@layout/layout_drawer_normal"/>
</android.support.v4.widget.DrawerLayout>
複製代碼
最終的效果爲:
DrawerLayout
和Toolbar
延伸到狀態欄上方若是咱們但願側滑菜單的區域可以延伸到狀態欄,那麼能夠進行如下三步的修改:
Activity
的style
,讓狀態欄透明,並修改狀態欄的顏色:<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>
<!-- 修改狀態欄顏色 -->
<item name="colorPrimaryDark">@android:color/holo_green_dark</item>
<!-- 狀態欄透明 -->
<item name="android:windowTranslucentStatus">true</item>
</style>
</resources>
複製代碼
Activity
根佈局設置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="我是內容佈局"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</FrameLayout>
</LinearLayout>
<!-- 側滑佈局 -->
<include layout="@layout/layout_drawer_normal"/>
</android.support.v4.widget.DrawerLayout>
複製代碼
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="我是側滑佈局"
android:layout_gravity="center"
android:textColor="@android:color/white"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
複製代碼
經過以上三步,就能夠達到沉浸式狀態欄的效果:
NavigationView
Navigation
屬性在使用DrawerLayout
的時候,咱們能夠隨意定義側滑菜單的佈局,NavigationView
其實就是Google
推薦的側滑佈局應該有的樣子,它的效果相似於下面這樣:
Navigation
的簡單例子:
<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
各屬性對應到下圖中就是這樣:
Navigation
分爲兩個部分:頭部和列表。
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>
複製代碼
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="錢包"/>
<item
android:id="@+id/photo"
android:icon="@mipmap/ic_launcher"
android:title="相冊"/>
<item
android:id="@+id/file"
android:icon="@mipmap/ic_launcher"
android:title="文件"/>
</menu>
複製代碼
menu
當中的每一個item
就對應於列表當中的一項,而item
的icon
和title
則分別對應列表項的圖標和文字,若是但願對item
進行分組,那麼能夠採用group
的方式來組織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>
複製代碼
不一樣組之間就會被分割線隔開:
若是想要給某個分組添加標題,那麼能夠採用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>
複製代碼
Navigation
點擊監聽若是但願處理Navigation
中列表的監聽,那麼可使用現成的接口,根據item
的id
來判斷是點擊的是列表中的哪一項。
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;
}
});
複製代碼
NavigationView
並無提供頭部點擊的監聽回調,所以,咱們只可以經過findViewById
的方法找到對應的View
,對其設置監聽,下面是整個headerLayout
在NavigationView
中的層次:
Android 5.0 之 NavigationView 的使用