前言

在Android开发的过去几年中,在公司的项目中一直没有机会尝试单Activity多Fragment的开发模式,随着Google推出Navigation组件,我意识到,终于有机会学习一种全新的开发模式了。

与上一篇文章相同,本篇同样是Navigation的初探,会用尽可能简洁的方式来了解Navigation,让我们对Navigation有一个初步印象,不会长篇大论或者源码轰炸,导致干货太多引起阅读困难。

目录

  • Navigation简介
  • Navigation的组成
  • Navigation实践

正文

Navigation简介

Navigation又称导航组件,主要负责应用内导航,也就是我们常说的屏幕切换。应用导航是Android开发中很重要的一部分,过去我们一般通过Intent或Fragment事物来实现应用内导航,使用场景也比较简单,点击按钮切换屏幕即可。

但是当场景变得复杂后,导航的管理就会便得十分困难。比如App首页常见的底部导航模式,不仅要确保用户在点击底部导航栏后,应用界面可以正常跳转,而且还需要突出显示正确的按钮,在处理返回栈的时候,也同样需要注意这个问题。而新的导航组件,就可以出色的解决这类复杂的问题。

通过引入navigation,我们可以轻松地使用navigation完成以下工作:

  • 简化常见导航模式的设置工作
  • 管理返回栈
  • 自动处理fragment事务
  • 简化类型安全参数传递
  • 管理转场动画
  • 轻松设置深度链接

同时navgation中引入了一种全新的资源文件,还可以集中种存储并可视化导航信息,极大程度地方便了开发人员对于屏幕切换的管理。

Navigation的组成

一个完整的Navigation由导航图、导航容器、导航控制器三个部分组成,下面分别来讲解这三个部分:

  • 导航图
    是一个新增的资源类型,它是一个XML文件,用于集中保存所有导航相关的信息,在Android Studio 3.3中提供了新的导航编辑器,能够可视化这些信息。在开发中,我们可以把它当作一款创建视图的图片编辑器。

android jetpack 不能用java 吗 android jetpack应用指南pdf_android studio

在导航图中,一个屏幕代表一个destination(目的地),也就是导航指向的下一个视图,单Activity的开发中,可以利用Fragment来创建destination。
选中一个destionation后,我们可以定义深层链接URL和启动选项等等

导航图中的箭头叫做action,代表您可以在应用中使用的几条导航路径,选中其中一个action后,我们就能看到一组内嵌信息,包括各个destionation间传递的信息、转场动画、返回栈操作等

  • 导航容器
    导航容器是一个name为NavHostFragment的fragment布局,它的本质就是一个导航界面的容器,用来动态替换应用中各个destionnation所代表的fragment。我们需要在布局中添加这个Fragment widget,如图所示:
<fragment
    android:id="@+id/host"
    android:name="androidx.navigation.fragment.NavHostFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:defaultNavHost="true"
    app:navGraph="@navigation/aac_graph" />

 

  • 导航图支持在Android studio3.3中进行可视化操作,在使用navigation时,建议将Android studio升级到3.3及以上的版本。
  • 导航控制器
    导航控制器用于设定导航组件行为与方向的组件,我们需要在java或者kotlin代码中为每一个NavHostFragment添加对应的NavController,以便管理和控制具体的导航行为。
Navigation.findNavController(it).navigate(R.id.navi2Fragment)
  • 通过添加 navController.navigate(R.id.xxx),navcontroller就会根据导航图中的信息来执行相应的导航操作,并最终把需要显示的fragment切换到NavHostFragment中。

Navigation实践

简单介绍了Navigation的组成后,我们通过完成一个底部导航,来继续深入了解Navigation的使用。

1.引入Navigation依赖

根据项目使用的语言,在module的build.gradle中添加对于语言的依赖

dependencies {
  def nav_version = "2.0.0"
  def nav_version_ktx = "2.0.0"

  // Java
  implementation "androidx.navigation:navigation-fragment:$nav_version"
  implementation "androidx.navigation:navigation-ui:$nav_version"

  // Kotlin
  implementation "androidx.navigation:navigation-fragment-ktx:$nav_version_ktx"
  implementation "androidx.navigation:navigation-ui-ktx:$nav_version_ktx"

}

 

2.创建导航图

在res文件夹下新建一个名为navigation的资源文件夹

android jetpack 不能用java 吗 android jetpack应用指南pdf_Android_02

然后在navigation中新建导航图,名称任意,这里使用module的名称加一个graph后缀

android jetpack 不能用java 吗 android jetpack应用指南pdf_android studio_03

 

3.创建导航容器

新建一个Activity用于管理fragment,同时创建对应的布局文件,activity布局文件中包含一个导航容器fragemnt,和一个底部BottomNavigationView。

<?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:layout_width="match_parent"
    android:layout_height="match_parent">

    <fragment
        android:id="@+id/content"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:defaultNavHost="true"
        app:layout_constraintBottom_toTopOf="@+id/bottomNavigationView"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:navGraph="@navigation/aac_graph" />

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/bottomNavigationView"
        android:layout_width="0dp"
        android:layout_height="55dp"
        android:background="@android:color/white"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:menu="@menu/main_menu" />
</androidx.constraintlayout.widget.ConstraintLayout>

 activity中将工作托管给具体的NavController,它可以确保返回栈中的所有导航工作都遵循MD最佳实践

class NavigationActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_navigation)

        val host: NavHostFragment = supportFragmentManager!!.findFragmentById(R.id.content) as NavHostFragment?
                ?: return
        val navController = host.navController

        val bottomNav = findViewById<BottomNavigationView>(R.id.bottomNavigationView)
        bottomNav?.setupWithNavController(navController)
    }
}

4.新建fragment选项卡,修改导航图

新建四个fragment,具体的内容可以任意,只是用作选项卡。

android jetpack 不能用java 吗 android jetpack应用指南pdf_android_04

然后打开导航图,将新增的4个fragment选项卡添加进入导航图中 

android jetpack 不能用java 吗 android jetpack应用指南pdf_android_05

到此为止,一个底部导航可以动态切换的首页就完成了,是不是比我们平常使用fragment事务的写法要简单很多?