在很多APP中可以看到如下圖從螢幕側邊拉出抽屜的畫面

此功能是由DrawerLayout為基底,加上NavigationView組合而成。
下面介紹如何實作這項功能:
這次是要做出如圖的功能↓

1.布局Layout:由DrawerLayout為基底,加上自己的布局與NavigationView
<?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:id="@+id/drawerLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
android:paddingTop="20dp"
android:theme="?attr/actionBarTheme"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.navigation.NavigationView
android:id="@+id/navigationView"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="@layout/drawer_header"
app:insetForeground="@android:color/transparent"
app:menu="@menu/home_drawer">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="bottom"
android:orientation="vertical"
android:paddingLeft="20dp"
android:paddingRight="20dp"
android:paddingBottom="10dp">
<Button
android:id="@+id/btn_logout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="登出" />
</LinearLayout>
</com.google.android.material.navigation.NavigationView>
</androidx.drawerlayout.widget.DrawerLayout>
其中,DrawerLayout底下包了兩個View,ConstraintLayout是我們的主畫面區域,NavigationView是側邊欄畫面區域。
注意:需要有個Toolbar,才能將側邊欄的開關綁定上去,不然就只能用手勢拖拉了! (或是自己做)
NavigationView的屬性中:
app:headerLayout=”@layout/drawer_header” 是Herder部分的畫面(用不到就非必要)
app:menu=”@menu/home_drawer” 是按鈕清單的畫面(用不到就非必要)
以上兩個畫面下面會解釋。
NavigationView中包的LinearLayout這裡是作為Footer來使用,放置登出功能,或是版本號之類..
在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"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageButton
android:id="@+id/ibtn_DrawerHeader_close"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginStart="16dp"
android:layout_marginTop="48dp"
android:adjustViewBounds="true"
android:background="?android:attr/selectableItemBackgroundBorderless"
android:padding="5dp"
android:scaleType="fitCenter"
android:src="@android:drawable/ic_menu_close_clear_cancel"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:text="item1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/ibtn_DrawerHeader_close" />
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:text="item2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button" />
<Button
android:id="@+id/button3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="40dp"
android:text="item3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button2" />
</androidx.constraintlayout.widget.ConstraintLayout>
建立了一個ImageButton與三個Button放在Header中。
在home_drawer.xml Menu佈局中:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/menu1"
android:title="menu1" />
<item
android:id="@+id/menu2"
android:title="menu2" />
</menu>
建立了兩個item供點選。
到這邊為止,Layout的設計準備就完成了。
2.程式碼實作:
class HomeActivity : AppCompatActivity() {
private lateinit var mNavigationView: NavigationView
private lateinit var mToolbar: Toolbar
private lateinit var actionBarDrawerToggle: ActionBarDrawerToggle
private lateinit var mDrawerLayout: DrawerLayout
private lateinit var btnLogout: Button
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home)
//綁定每項元件
mDrawerLayout = findViewById(R.id.drawerLayout)
mToolbar = findViewById(R.id.toolbar)
mNavigationView = findViewById(R.id.navigationView)
btnLogout = findViewById(R.id.btn_logout)
//側邊欄綁定至 Toolbar
setSupportActionBar(mToolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(false)
supportActionBar?.setHomeButtonEnabled(true)
actionBarDrawerToggle = object : ActionBarDrawerToggle(
this,
mDrawerLayout,//側邊欄的Layout
mToolbar,//綁定側邊欄的Toolbar
R.string.drawer_open,//字串檔新增開起字串
R.string.drawer_close//同上
){ //側邊欄開啟關閉的動作
override fun onDrawerClosed(view: View){
super.onDrawerClosed(view)
//當側邊欄關閉
}
override fun onDrawerOpened(drawerView: View){
super.onDrawerOpened(drawerView)
//當側邊欄開啟
}
}
actionBarDrawerToggle.syncState()
mDrawerLayout.addDrawerListener(actionBarDrawerToggle)
//側邊欄項目(menu)點擊的動作
mNavigationView.setNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.menu1 -> {
Toast.makeText(this@HomeActivity, "點了menu1", Toast.LENGTH_SHORT).show()
}
R.id.menu2 -> {
Toast.makeText(this@HomeActivity, "點了menu2", Toast.LENGTH_SHORT).show()
}
}
item.isCheckable = false
//點擊後關閉側邊欄
mDrawerLayout.closeDrawer(GravityCompat.START)
return@setNavigationItemSelectedListener true
}
//側邊欄Footer的元件監聽
btnLogout.setOnClickListener {
mDrawerLayout.closeDrawer(GravityCompat.START)
Toast.makeText(this, "登出", Toast.LENGTH_LONG).show()
}
//取得側邊欄Header的元件
val headerLayout: View = mNavigationView.getHeaderView(0)// index 0 = HeaderView
//監聽Header的元件
val ibtnClose: ImageButton = headerLayout.findViewById(R.id.ibtn_DrawerHeader_close)
ibtnClose.setOnClickListener {
mDrawerLayout.closeDrawer(GravityCompat.START)
Toast.makeText(this, "關閉", Toast.LENGTH_LONG).show()
}
}
}
按返回鍵時優先關閉側邊欄
override fun onBackPressed() {
// super.onBackPressed()
//如果側邊欄開著就先關閉側邊欄
if(dlDrawerLayout.isDrawerOpen(GravityCompat.START)){
dlDrawerLayout.closeDrawer(GravityCompat.START)
}else{
finish()
}
}
-待續-
發佈留言