本篇我們使用 Material Design來實現滑動菜單。
首先在我們的應用程序中添加DrawerLayout依賴:
要在我們的程序中使用DrawerLayout,首先我們的使用DrawerLayout爲頂層佈局,該佈局內一般有兩個組件,第一個一般是FrameLayout顯示屏幕中央內容,第二個是我們的的滑動菜單內容。比如我們今天要修改的NoteListFragment。按照上面的格式我們新的佈局文件如下:
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.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:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/drawer_layout_list">
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".fragment.NoteListFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/note_recycle_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_note_list_empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/note_list_empty"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:text="this is a menu drawer"
android:background="#FFF"/>
</androidx.drawerlayout.widget.DrawerLayout>
那麼android又是如何來判斷DrawerLayout內的組件哪個是我們的滑動菜單呢?
這裏我們需要說明一下那就是android會通過android:layout_gravity屬性進行判斷。官方文檔說明有第一個組件不要設置該屬性,第二個組件設置對應的屬性即可,如上例。
如果兩個組件都設置了同樣的android:layout_gravity,如下所示:
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
tools:context=".fragment.NoteListFragment">
</androidx.constraintlayout.widget.ConstraintLayout>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="start"
android:background="#FFF"
android:text="this is a menu drawer" />
也就是說我們需要設置不同的android:layout_gravity屬性即可。比如我們一個left,一個right:
通常我們只需要一個滑動菜單,所以第一個一般使用FragmentLayout用來顯示我們的內容頁面。
當然了,只是在佈局文件中設置是沒有上圖中那個home的圖標的,這裏還需要在代碼中進行設置一下。修改NoteListFragment的initFragmentView方法,追加下面的代碼:
ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
if (actionBar != null) {
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setHomeAsUpIndicator(R.drawable.ic_menu_note_home);
}
setDisplayHomeAsUpEnabled用來設置顯示左上角圖標,setHomeAsUpIndicator用來指定自定義的圖標。
如果我們要響應該菜單的選擇事件,那麼記得這個的id一定是android.R.id.home:
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
drawerLayout.openDrawer(GravityCompat.START);
return true;
case R.id.menu_note_create:
Intent intent = new Intent(getActivity(), NoteCreateActivity.class);
startActivityForResult(intent, 2);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
讓我們看一張效果圖:
這個樣子得菜單似乎比我們的漂亮多了,幸運的是在android中我們可以通過NavigationView來實現相應的效果。
首先我們的導入依賴庫:
接下來我們使用NavigationView替換上面的TextView:
<com.google.android.material.navigation.NavigationView
android:id="@+id/navigation"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start" />
此時我們的菜單還什麼都沒有。
接下來我們需要利用 app:headerLayout和 app:menu屬性設置header和menu。
創建佈局文件drawer_header.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/drawer_background"
android:padding="20dp">
<de.hdodenhof.circleimageview.CircleImageView
android:id="@+id/img_note_logo"
android:layout_width="70dp"
android:layout_height="70dp"
android:src="@drawable/logo"
app:civ_border_color="@color/colorPrimary"
app:civ_border_width="1dp"
app:layout_constraintBottom_toTopOf="@id/tv_note_app_name"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tv_note_app_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:text="@string/app_name"
android:textColor="@color/colorPrimary"
android:textSize="18sp"
app:layout_constraintBottom_toTopOf="@id/tv_note_introduce"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/img_note_logo" />
<TextView
android:id="@+id/tv_note_introduce"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:text="@string/app_introduce"
android:textColor="@color/colorPrimary"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_note_app_name" />
</androidx.constraintlayout.widget.ConstraintLayout>
指定app:headerLayout爲我們剛創建的佈局文件:
app:headerLayout="@layout/drawer_header"
剩下就是添加我們的menu了。
<?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/menu_home"
android:icon="@drawable/ic_menu_note_home"
android:title="@string/note_home" />
<item
android:id="@+id/menu_settings"
android:icon="@drawable/ic_menu_note_settings"
android:title="@string/note_settings" />
<item
android:id="@+id/menu_about"
android:icon="@drawable/ic_menu_note_about"
android:title="@string/note_about" />
<item
android:id="@+id/menu_feedback"
android:icon="@drawable/ic_menu_note_feedback"
android:title="@string/note_feedback" />
</group>
</menu>
同樣別忘記設置app:menu屬性:
app:menu="@menu/menu_drawer"
同樣的,如果想爲這些菜單添加點擊事件,那麼我們需要實現下面的方法:
@Override
protected void initFragmentListener() {
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
Log.d(TAG, "onNavigationItemSelected: " + item.getTitle());
return false;
}
});
}
當然了,如果還需要處理header處的事件,可以使用getHeaderView(0)方法獲取根view,然後通過findViewById方法獲取到內部的控件進行設置。
ImageView imageView = navigationView.getHeaderView(0).findViewById(R.id.img_note_logo);
TextView textView = navigationView.getHeaderView(0).findViewById(R.id.tv_note_app_name);
imageView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "onClick: imageview");
}
});
textView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.d(TAG, "onClick: textview");
}
});