前言
在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中提供了新的导航编辑器,能够可视化这些信息。在开发中,我们可以把它当作一款创建视图的图片编辑器。
在导航图中,一个屏幕代表一个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的资源文件夹
然后在navigation中新建导航图,名称任意,这里使用module的名称加一个graph后缀
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,具体的内容可以任意,只是用作选项卡。
然后打开导航图,将新增的4个fragment选项卡添加进入导航图中
到此为止,一个底部导航可以动态切换的首页就完成了,是不是比我们平常使用fragment事务的写法要简单很多?