如何为安卓应用编写一个导航抽屉的代码

805 阅读8分钟

Final product image

你要创建的东西

谷歌的Material Design团队对Android中的导航抽屉的功能定义如下。

导航抽屉从左边滑入,包含你的应用程序的导航目的地。

一个实现了导航抽屉菜单设计的流行安卓应用的例子是谷歌的收件箱应用,它使用导航抽屉来导航不同的应用部分。如果你的设备上还没有收件箱应用,你可以自己从Google Play商店下载收件箱应用来检查。下面的截图显示了导航抽屉拉开后的收件箱。

navigation drawer android

当用户从活动的左侧边缘用手指滑动时,可以查看导航抽屉。他们也可以通过点击操作栏中的应用图标(也被称为安卓的 "汉堡包 "菜单),从主活动(应用程序的最高层)中找到它。

请注意,如果你的应用程序中有许多不同的目的地(例如超过六个),建议你使用导航抽屉菜单设计。

在这篇文章中,你将学习如何在Android的导航抽屉内显示导航项。我们将介绍如何使用Jetpack导航来完成这项任务。作为奖励,你还将学习如何使用Android Studio的模板功能,用导航抽屉快速引导你的项目。

前提条件

为了能够学习这个Android Studio导航抽屉的教程,你需要:

创建一个Android Studio项目

启动Android Studio并创建一个新的项目(你可以把它命名为NavigationDrawer ),其中有一个空的活动叫MainActivity 。请确保也选择Kotlin 语言。

Create empty activity

添加项目的依赖性

对导航的支持需要一些依赖项。打开应用程序的build.gradle文件,添加以下依赖项

dependencies {
    def lifecycle_version = "2.2.0"
    implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
    ...
}

同时将素材库添加到项目中。

dependencies {
    ...
    implementation "com.google.android.material:material:$version"
    ...
}

同步项目文件以使变化生效。

创建DrawerLayout

为了在我们的应用程序的所有目的地显示抽屉图标,我们将使用DrawerLayout 组件。打开main_acivity.xml并添加DrawerLayout 作为根视图。抽屉布局将承载两个子视图,NavHostFragmentNavigationView

<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="https://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">

<!--TOOLBAR HERE-->


<!--NavHostFragment HERE-->
       
<!--NavigationView HERE-->
       
</androidx.drawerlayout.widget.DrawerLayout>


这里我们创建了一个ID为drawer_layoutDrawerLayout widget。当XML布局在Android Studio设计视图中打开时,tools:openDrawer 属性被用来显示导航抽屉的切换。

官方文档DrawerLayout 有如下说明:

DrawerLayout 作为窗口内容的顶层容器,允许从窗口的一个或两个垂直边缘拉出交互式 "抽屉 "视图。

在添加了DrawerLayout widget之后,我们包含了一个子布局,app_bar_main.xml,它指向工具条布局。

<!--main_activity.xml-->
<?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/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">

    <include
        layout="@layout/app_bar_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />


<!--NavHostFragment HERE-->
       
<!--NavigationView HERE-->
       
</androidx.drawerlayout.widget.DrawerLayout>

这里是我的app_bar_main.xml资源文件。这个文件有一个CoordinatorLayout ,一个AppBarLayout ,和一个Toolbar 小部件。

<!--tool_bar_layout.xml-->
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout 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=".MainActivity">

    <com.google.android.material.appbar.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:theme="@style/Theme.NavigationDrawer.AppBarOverlay">

        <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/Theme.NavigationDrawer.PopupOverlay" />

    </com.google.android.material.appbar.AppBarLayout>

</androidx.coordinatorlayout.widget.CoordinatorLayout>

创建一个导航图

导航图是一个XML资源文件,它包含了你的应用程序的所有目的地和动作,这些目的地通过动作连接。下面是一个显示五个片段的导航图的例子。

Nav graph showing 5 screens

输入显示5个屏幕的导航图

要添加一个导航图,在res目录上点击右键,选择新建>Android资源文件。在接下来的对话框中,选择导航作为资源类型。 并点击确定,一个新的XML文件nav_graph.xml将在导航文件夹中被创建,如下图所示。

创建导航图

添加NavHostFragment

一个导航宿主片段充当应用程序片段的宿主,当用户从一个目的地移动到另一个目的地时,根据需要将片段换入和换出。这些目的地必须在导航图中定义。

main_activity.xml文件中添加NavHostFragment ,并引用navGraph

<!--main_activity.xml-->
<?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/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">

    <include
        layout="@layout/app_bar_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />


<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>
       
<!--NavigationView HERE-->
       
</androidx.drawerlayout.widget.DrawerLayout>


在目的地图中添加片段

片段代表你的应用程序的所有目的地。在我们的例子中,我们将添加3个片段到导航图中。右键单击导航文件夹,打开nav_graph.xml。要添加一个片段,点击创建新的目的地,并填写其余的细节。

添加片段到导航图

重复同样的步骤,创建另外两个片段,即配置文件片段和设置片段。你的导航图现在应该是这样的。

navigation graph 添加一个NavigationView 组件

最后,让我们创建一个NavigationView 小部件。官方文档NavigationView 有如下描述。

NavigationView 代表一个标准的应用程序的导航菜单。菜单内容可以由一个菜单资源文件填充。

打开main_activity.xml并添加NavigationView

<!--main_activity.xml-->
<?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/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">

    <include
        layout="@layout/app_bar_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />


<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>
       
<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_main"
        app:menu="@menu/drawer_menu" />
       
</androidx.drawerlayout.widget.DrawerLayout>


NavigationView XML widget中,你可以看到我们添加了一个android:layout_gravity 属性,值为start 。这是用来定位抽屉的--你希望导航抽屉的菜单设计从左边或右边出来(在支持布局方向的平台版本上是起点或终点)。在我们自己的案例中,抽屉将从左边出来。

我们还包括一个app:headerLayout 属性,它指向@layout/nav_header_main 。这将添加一个View 作为导航菜单的标题。

下面是我的nav_header_main.xml布局资源文件

<?xml version="1.0" encoding="utf-8"?>
<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="@dimen/nav_header_height"
    android:gravity="bottom"
    android:orientation="vertical"
    android:theme="@style/ThemeOverlay.AppCompat.Dark">

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingTop="@dimen/nav_header_vertical_spacing"
        android:text="@string/nav_header_title"
        android:textAppearance="@style/TextAppearance.AppCompat.Body1" />

</LinearLayout>

为了包括导航抽屉的菜单项,我们可以使用属性app:menu ,其值指向一个菜单资源文件。

app:menu="@menu/drawer_menu" />

这里是res/menu/drawer_menu.xml菜单资源文件。

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:showIn="navigation_view">

    <group android:checkableBehavior="single">
        <item
            android:id="@+id/nav_home"
            android:icon="@drawable/home"
            android:title="@string/menu_home" />
        <item
            android:id="@+id/nav_gallery"
            android:icon="@drawable/person"
            android:title="@string/menu_gallery" />
        <item
            android:id="@+id/nav_slideshow"
            android:icon="@drawable/settings"
            android:title="@string/menu_slideshow" />
    </group>
</menu>

这里我们使用<menu> ,定义了一个Menu ,作为菜单项的容器。一个<item> 创建一个MenuItem ,它代表菜单中的一个项目。还需要注意的是,菜单项的id与匹配片段的id相对应。

注意,当显示来自菜单资源的导航列表项时,我们可以用一个ListView 来代替。但是,通过用菜单资源来配置导航抽屉,我们可以免费获得导航抽屉的材质设计风格如果你使用ListView ,你就必须维护列表,并对其进行样式设计,以满足导航抽屉的推荐材料设计规格

组件的初始化

接下来,我们要初始化所有组件的实例。初始化将发生在MainActivity.ktonCreate()

AppBarConfiguration 对象被用来管理导航抽屉按钮的行为。

private lateinit var appBarConfiguration: AppBarConfiguration

首先,我们使用setSupportActionBar() 方法将工具条设置为活动的应用条。

val toolbar: Toolbar = findViewById(R.id.toolbar)
        setSupportActionBar(toolbar)

接下来我们将所有片段设置为顶层目的地,这意味着在导航时它们将保持在后堆栈中。

 // Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
        appBarConfiguration = AppBarConfiguration(setOf(
                R.id.home_menu, R.id.profile_menu, R.id.settings_menu), drawerLayout)

该方法 setupActionBarWithNavController当目的地发生变化时,自动更新动作栏中的标题。

setupActionBarWithNavController(navController, appBarConfiguration)

设置好导航抽屉。

val navView: NavigationView = findViewById(R.id.nav_view)
val navController = findNavController(R.id.nav_host_fragment)
navView.setupWithNavController(navController)

最后,显示出现在应用栏左上角的向上按钮,这是通过使用onSupportNavigateUp 方法将导航控制器与应用栏整合在一起完成的。

MainActivity.kt的最终代码应该是这样的。

package com.example.navigationdrawer

// imports

class MainActivity : AppCompatActivity() {

    private lateinit var appBarConfiguration: AppBarConfiguration

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val toolbar: Toolbar = findViewById(R.id.toolbar)
        setSupportActionBar(toolbar)
        ///
        val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
        val navView: NavigationView = findViewById(R.id.nav_view)
        val navController = findNavController(R.id.nav_host_fragment)
        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        appBarConfiguration = AppBarConfiguration(setOf(
                R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow), drawerLayout)
        setupActionBarWithNavController(navController, appBarConfiguration)
        navView.setupWithNavController(navController)
    }


    override fun onSupportNavigateUp(): Boolean {
        val navController = findNavController(R.id.nav_host_fragment)
        return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
    }
}


测试应用程序

在这一点上,我们可以运行该应用程序了!

navigation drawer

奖励:使用Android Studio模板

现在你已经了解了创建导航抽屉所涉及的API,我将向你展示一个捷径,这将使你在下次使用时更加快捷。你可以简单地使用一个模板,而不是从头开始编码一个导航抽屉活动。

Android Studio提供了遵循Android设计和开发最佳实践的代码模板。这些现有的代码模板(可用于Java和Kotlin)可以帮助你快速启动你的项目。一个这样的模板可以用来创建一个导航抽屉活动。

我将向你展示如何在Android Studio中使用这一方便的功能。

对于一个新项目,启动Android Studio。

Android Navigation Drawer Design Tutorial Create Android Project dialog 输入应用程序的名称并点击 "下一步"按钮。

你可以保留默认值,因为它们在目标Android设备对话框中。再次点击 "下一步"按钮。

Android Navigation Drawer Design Tutorial Add an Activity to Mobile dialog 在 " 向移动设备添加 活动"对话框中,向下滚动并选择导航抽屉活动。 之后点击 "下一步"按钮。

Android Navigation Drawer Design Tutorial Configure Activity dialog

在最后一个对话框中,如果你愿意,你可以重命名活动名称、布局名称或标题。最后,点击 "完成"按钮接受所有配置。

现在Android Studio已经帮助我们创建了一个带有导航抽屉活动的项目。真的很酷!

我们强烈建议你去探索生成的代码。

你也可以使用已经存在的Android Studio项目的模板。只需转到文件>新建>活动>导航抽屉活动

Android Navigation Drawer Design Tutorial Navigation from file menu too Navigation Drawer Activity

总结

在本教程中,你学到了如何在Android中使用Jetpack Navigation从头开始创建一个导航抽屉菜单设计。我们还探讨了如何轻松快速地使用Android Studio模板来创建一个导航抽屉。