为什么要使用导航抽屉?
Android 导航抽屉是一个滑动菜单,用于显示应用程序中的重要链接。 导航抽屉可轻松在这些链接之间来回导航。 默认情况下它是不可见的,需要通过向左滑动或在 ActionBar 中单击其图标来打开它。 其易用性如下:
- 从活动左边缘滑动手指时,用户可以查看导航抽屉;
- 如果应用具有不同的界面(超过六个),则建议使用导航抽屉;
- 它使应用程序更具交互性和简洁性。
导航抽屉的组件构成
- DrawerLayout 组件的实例,抽屉的父布局容器
- 作为 DrawerLayout 的子级嵌入的 NavigationView 组件的实例,也就是抽屉主体
- 菜单资源文件,其中包含要在导航抽屉中显示结构和内容;
- 一个可选的布局资源文件,其中包含要显示在导航抽屉的标题部分中的内容;
- 分配给 NavigationView 的侦听器,用于检测用户何时选择了一项;
- 一个 ActionBarDrawerToggle 实例,一个按钮,用于将导航抽屉连接和同步到应用栏,通过点击打开导航抽屉;
导航抽屉的实现
在 app 的 build.gradle 文件中添加依赖:
implementation 'com.google.android.material:material:1.0.0'
,点击 Sync Now 等待同步完成;在 layout 中创建两个布局文件:
- content_main.xml,主布局文件
- nav_header.xml,抽屉顶部布局
在 res 新建文件夹 menu,并创建 nav_menu.xml 文件,构建抽屉菜单;
之后在 styles.xml 文件中添加主题:
1
2
3
4
5<style name="AppTheme.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
<item name="android:statusBarColor">@android:color/transparent</item>
</style>在AndroidManifest.xml 中,对 MainActivity 应用该主题:
1
2
3
4
5
6
7<activity android:name=".MainActivity"
android:theme="@style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>重写 MainActivity 对应的布局文件 activity_main.xml,引入之前创建的
content_main.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<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/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
layout="@layout/content_main"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<com.google.android.material.navigation.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header"
app:menu="@menu/nav_menu"/>
</androidx.drawerlayout.widget.DrawerLayout>编辑抽屉顶部 nav_header.xml 布局文件,布局仅是 app 的图标文件以及两行文字:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
<LinearLayout
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="200dp"
android:background="#4CAF50"
android:orientation="vertical"
android:gravity="bottom"
android:paddingLeft="15dp"
android:paddingBottom="15dp">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@mipmap/ic_launcher"
android:id="@+id/imageView"
android:layout_marginBottom="15dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Title"
android:textColor="#FFFFFF"
android:textStyle="bold"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is our navigation drawer"
android:textColor="#FFFFFF"/>
</LinearLayout>编辑抽屉菜单布局文件 nav_menu.xml,值得注意的是,当在使用 icon 时,可以利用 Android Studio 生成,在项目导航栏右击,选择
New => Vector Asset
即可;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group>
<item
android:id="@+id/nav_profile"
android:icon="@drawable/ic_profile"
android:title="Profile"/>
<item
android:id="@+id/nav_messages"
android:icon="@drawable/ic_messages"
android:title="Messages"/>
<item
android:id="@+id/nav_friends"
android:icon="@drawable/ic_friends"
android:title="Friends"/>
</group>
<item android:title="Account Settings">
<menu>
<item
android:id="@+id/nav_update"
android:icon="@drawable/ic_update"
android:title="Update Profile"/>
<item
android:id="@+id/nav_logout"
android:icon="@drawable/ic_signout"
android:title="Sign Out"/>
</menu>
</item>
</menu>编辑 content_main.xml 主布局文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.material.appbar.AppBarLayout
android:layout_height="wrap_content"
android:layout_width="match_parent" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Navigation Drawer"
android:textColor="#FFFFFF"
style="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"/>
</LinearLayout>
</androidx.appcompat.widget.Toolbar>
</com.google.android.material.appbar.AppBarLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="This is my content area."/>
</LinearLayout>
</LinearLayout>最后编辑MainActivity.kt 文件,将视图绑定到业务逻辑:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
// 声明控件并在 onCreate() 中初始化
lateinit var toolbar: Toolbar
lateinit var drawerLayout: DrawerLayout
lateinit var navView: NavigationView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar)
drawerLayout = findViewById(R.id.drawer_layout)
navView = findViewById(R.id.nav_view)
// 创建 ActionBarDrawerToggle 对象
val toggle = ActionBarDrawerToggle(
this, drawerLayout, toolbar, 0, 0
)
// 建立 DrawerLayout 和 ActionBarDrawerToggle 的关联
drawerLayout.addDrawerListener(toggle)
toggle.syncState()
navView.setNavigationItemSelectedListener(this)
}
// 重载接口方法
override fun onNavigationItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.nav_profile -> {
Toast.makeText(this, "Profile clicked", Toast.LENGTH_SHORT).show()
}
R.id.nav_messages -> {
Toast.makeText(this, "Messages clicked", Toast.LENGTH_SHORT).show()
}
R.id.nav_friends -> {
Toast.makeText(this, "Friends clicked", Toast.LENGTH_SHORT).show()
}
R.id.nav_update -> {
Toast.makeText(this, "Update clicked", Toast.LENGTH_SHORT).show()
}
R.id.nav_logout -> {
Toast.makeText(this, "Sign out clicked", Toast.LENGTH_SHORT).show()
}
}
drawerLayout.closeDrawer(GravityCompat.START)
return true
}
}ActionBarDrawerToggle:其构造函数为:
1
2
3
4
5
6ActionBarDrawerToggle(
activity: Activity!,
drawerLayout: DrawerLayout!,
toolbar: Toolbar!, // 没有 Toolbar 时省略
Int, // 这两个参数与 Accessibility 服务有关,便于视力不好的用户使用 openDrawerContentDescRes:
Int) // 感兴趣可以谷歌 closeDrawerContentDescRes:syncState():将抽屉指示器/功能的状态与链接的DrawerLayout同步
closeDrawer():用Gravity.LEFT键关闭左抽屉,或用Gravity.RIGHT键关闭右抽屉。 也可以使用GravityCompat.START或GravityCompat.END。