側(cè)滑菜單:DrawerLayout
側(cè)滑菜單是用來在頁面上增加一個抽屜式菜單欄的控件,它一般位于左側(cè),用戶可以通過側(cè)滑拉出或者關(guān)閉。通常你可以放置一些菜單項或者上下文相關(guān)的設置在里面,幫助你節(jié)省屏幕空間同時可以很方便的隨時打開。側(cè)滑菜單其實就是下面這貨:
1. 側(cè)滑菜單的特性
側(cè)滑菜單在 Andriod 應用中非常常見,但是當你想探究實現(xiàn)方法的時候會發(fā)現(xiàn)很多早期教程都會教你使用第三方庫,或者手把手教你通過一個 ListView 配合手勢加上動畫來實現(xiàn)。好消息是現(xiàn)在官方已經(jīng)推出了一個專門用于側(cè)滑的控件——DrawerLayout。
DrawerLayout 作為頁面內(nèi)容的頂層容器,讓用戶通過側(cè)滑手勢從屏幕邊緣拉出。我們可以給它的子 View 設置layout_gravity
屬性來決定抽屜是從左側(cè)或者右側(cè)打開。
2. DrawerLayout 使用方法
DrawerLayout 作為官方提供的控件,使用起來還是很簡單的,如果查看 DrawerLayout 的源碼,可以發(fā)現(xiàn) DrawerLayout 是直接繼承至 ViewGroup 寫的,所以在它內(nèi)部可以承載其他的 View 同時還會有一些附屬的功能。我們通常將 DrawerLayout 用做根View,然后將首頁要展示的內(nèi)容放在 DrawerLayout 的最前面作為第一個子 View,并且高度、寬度設置為match_parent
。
2.1 DrawerLayout 的常用屬性
DrawerLayout 的特有屬性非常少,常用的基本上就是在前文提到過的一個:layout_gravity,它的作用是指定側(cè)滑菜單的滑動方向,常用的有以下兩個值:
- start: 從左側(cè)劃出的菜單
- end: 從右側(cè)劃出的菜單
該屬性是作用在 DrawerLayout 的子 View 之上的,設置了layout_gravity
屬性的子 View 將作為一個側(cè)滑菜單使用。
2.2 DrawerLayout 的常用 API
常用 API 只有一個,用來監(jiān)聽策劃菜單的滑動事件:
public void addDrawerListener(DrawerListener listener)
接口中有以下幾個方法:
- public void onDrawerSlide(View drawerView, float slideOffset)
當側(cè)滑菜單滑動過程中調(diào)用,傳入滑動的 View 對象及滑動的距離 - public void onDrawerOpened(View drawerView)
當側(cè)滑菜單打開的時候調(diào)用 - public void onDrawerClosed(@NonNull View drawerView)
當側(cè)滑菜單關(guān)閉的時候調(diào)用 - public void onDrawerStateChanged(int newState)
當側(cè)滑菜單滑動狀態(tài)變化時調(diào)用
整體而言,官方已經(jīng)為我們封裝的非常好了,所以使用也比較簡單,只需要掌握這幾個屬性和 API,就可以輕松設置屬于你自己的側(cè)滑菜單了,接下來我們一起實現(xiàn)一個 DrawerLayout 示例。
3 DrawerLayout 的使用示例
本節(jié)我們通過 DrawerLayout 實現(xiàn)一個左側(cè)的側(cè)滑菜單,仍然借用“水果”作為案例(提醒大家注意健康)。在 DrawerLayout 中放置一個 ListView 作為側(cè)滑菜單載體,用戶通過在 ListView 上選擇從而更新主頁面的內(nèi)容。
3.1 編寫主頁面布局
整體的頁面布局對按照第 2 小節(jié)所講的規(guī)則來編寫,包含幾個元素:主頁面標題、主頁面內(nèi)容、側(cè)滑菜單。布局代碼如下:
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.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">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/drawer_prompt"
android:textSize="30sp" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:gravity="center"
android:text="側(cè)滑菜單" />
<ImageView
android:id="@+id/imageview"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<ListView
android:id="@+id/left_drawer"
android:layout_width="240dp"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#FFFFFF"
android:choiceMode="singleChoice"
android:divider="@android:color/darker_gray"
android:dividerHeight="1dp" />
</androidx.drawerlayout.widget.DrawerLayout>
3.2 編寫列表布局
接著就是要針對 ListView 編寫一個列表樣式了,學過 ListView 的同學想必都不在話下,如果對 ListView 不熟悉的可以回顧一下第 24 節(jié)的內(nèi)容,這里我們新建 list_item.xml 文件,用最經(jīng)典的 TextView 搭配 ImageView 的方式:
<?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="100dp"
android:gravity="center"
android:orientation="horizontal"
android:background="?android:attr/activatedBackgroundIndicator"
android:minHeight="?android:attr/listPreferredItemHeightSmall"
android:padding="10dp" >
<ImageView
android:id="@+id/imageViewIcon"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:paddingRight="10dp" />
<TextView
android:id="@+id/textViewName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:textColor="@android:color/black"
android:textAppearance="?android:attr/textAppearanceListItemSmall" />
</LinearLayout>
3.3 編寫 ListView 適配器
其實整個項目針對 DrawerLayout 的操作并不多,更多的是在實現(xiàn) ListView,這也體現(xiàn)了 Google 大佬們經(jīng)典的封裝能力。有了 ListView 布局就需要添加一個 Adapter,以供將 UI 和 數(shù)據(jù)綁定到一起。
package com.emercy.myapplication;
import android.view.View;
import android.view.ViewGroup;
import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class MyAdapter extends ArrayAdapter<Model> {
Context mContext;
int layoutResourceId;
Model data[];
public MyAdapter(Context mContext, int layoutResourceId, Model[] data) {
super(mContext, layoutResourceId, data);
this.layoutResourceId = layoutResourceId;
this.mContext = mContext;
this.data = data;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View listItem = convertView;
LayoutInflater inflater = ((Activity) mContext).getLayoutInflater();
listItem = inflater.inflate(layoutResourceId, parent, false);
ImageView imageViewIcon = (ImageView) listItem.findViewById(R.id.imageViewIcon);
TextView textViewName = (TextView) listItem.findViewById(R.id.textViewName);
Model folder = data[position];
imageViewIcon.setImageResource(folder.icon);
textViewName.setText(folder.name);
return listItem;
}
}
3.4 編寫 MainActivity 主邏輯
最后就可以進入主邏輯的編寫,我們需要初始化列表數(shù)據(jù),然后通過 Adapter 與 ListView 綁定,然后監(jiān)聽列表的點擊也就是用戶的選擇,再點擊的時候主頁面做出相應的改變即可。
package com.emercy.myapplication;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ImageView;
import android.widget.ListView;
public class MainActivity extends Activity {
private ListView mDrawerList;
private ImageView mImage;
Model[] mItem = new Model[3];
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mDrawerList = (ListView) findViewById(R.id.left_drawer);
mImage = findViewById(R.id.imageview);
mItem[0] = new Model(R.drawable.apple, "蘋果");
mItem[1] = new Model(R.drawable.peach, "桃子");
mItem[2] = new Model(R.drawable.watermelon, "西瓜");
MyAdapter adapter = new MyAdapter(this, R.layout.list_item, mItem);
mDrawerList.setAdapter(adapter);
mDrawerList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mImage.setImageResource(mItem[position].icon);
}
});
}
}
最后我們編譯運行,會發(fā)現(xiàn)整個頁面只有一個“選擇水果”的提示信息,不著急,側(cè)滑菜單當然是默認隱藏的,我們通過在屏幕左側(cè)側(cè)滑來請它出山,最終效果如下:
4. 小結(jié)
本節(jié)介紹了官方出品的一個側(cè)滑菜單控件,它是直接繼承自 ViewGroup 實現(xiàn)的,通常我們會把它作為整個頁面的根布局,然后將主頁面作為 DrawerLayout 的第一個子 View。接著為需要側(cè)滑的列表添加layout_gravity
屬性,最后按照需要添加一個監(jiān)聽器,就可以完成側(cè)滑功能了。在 DrawerLayout 出來之前,有各式各樣第三方的側(cè)滑控件,大家可以翻看一些比較古老的帖子或者教程學習學習,但是使用上還是推薦使用官方 DrawerLayout 控件,在細節(jié)和封裝以及后期維護上還是很具有優(yōu)勢的。