Android 官方架构组件 Navigation 使用详解
前言
前段时间,我在做项目开发的时候对Fragment的管理遇到几个小问题,总觉得在现阶段封装好的Fragment管理器不太优雅。这成为我下决心学习Jetpack在很早之前推出的Navigation库,该库的诞生就是为了能够更加优雅的管理Fragment。在学习新知识时,我比较喜欢将我遇到的知识点与难点写在纸上。但有时由于时间比较紧,记在纸上的东西往往没有那么的详细与具体。所以我决定以后通过以写博客的方式对知识进行一个归纳总结,也希望能帮助到在看这篇博客的你。让我们一起来完善Android的知识体系吧!
使用条件
如果您要在 Android Studio 中使用 Navigation 组件,则必须使用 Android Studio 3.3 或更高版本。
添加依赖
要在您的项目中添加 Navigation 支持,请向应用的 build.gradle 文件添加以下依赖项:
dependencies {//...implementation "androidx.navigation:navigation-fragment-ktx:2.2.1"implementation "androidx.navigation:navigation-ui-ktx:2.2.1"
}
使用Navigation的具体流程
项目演示
新建三个Framgnet
在配置Navigation之前,我们创建三个Framgnet用于测试。代码如下所示:
//第一个Fragment
class Page1Fragment : Fragment() {override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View? {return inflater.inflate(R.layout.fragment_page_1, container, false)}
}
//第二个Framgnet
class Page2Fragment : Fragment() {override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View? {return inflater.inflate(R.layout.fragment_page_2, container, false)}
}
//第三个Fragment
class Page3Fragment : Fragment() {override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View? {return inflater.inflate(R.layout.fragment_page_3, container, false)}
}
配置导航
- 我们需要在res文件夹下新建一个navigaton文件夹。
- 在navigaton文件夹下创建一个navigation资源文件。
- 我们将它起名为mobile_navigaion.xml。
如下图所示:
在<navigation>
标签里可以嵌套另一个<navigation>
标签,也可以新建一个navigation xml文件,通过<include>
将其引进来。
在mobile_navigation.xml中添加上我们刚创建好的三个Fragment。
在<fragment>
标签下要有id,name,label与layout,这四个属性一定要齐全!代码如下所示:
<?xml version="1.0" encoding="utf-8"?>
<navigation 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/mobile_navigation"><fragmentandroid:id="@+id/fragment_page_1_id"android:name="com.johnlion.navigation.Page1Fragment"android:label="fragment_page_1_label"tools:layout="@layout/fragment_page_1" /><fragmentandroid:id="@+id/fragment_page_2_id"android:name="com.johnlion.navigation.Page2Fragment"android:label="fragment_page_2_label"tools:layout="@layout/fragment_page_2" /><fragmentandroid:id="@+id/fragment_page_3_id"android:name="com.johnlion.navigation.Page3Fragment"android:label="fragment_page_1_label"tools:layout="@layout/fragment_page_3" /></navigation>
此时我们刚添加完Fragment的mobile_navigation.xml中,<navigation>
标签在android studio编译器中会报红色警告,这是由于我们并未在Activity布局文件中添加好NavHostFragment。
我们打开Activity布局文件,并在布局文件中添加一个NavHostFragment。代码如下所示:
<?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"tools:context=".MainActivity"><fragmentandroid:id="@+id/nav_host_fragment"android:name="androidx.navigation.fragment.NavHostFragment"android:layout_width="0dp"android:layout_height="0dp"app:defaultNavHost="true"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"app:navGraph="@navigation/mobile_navigation" /></androidx.constraintlayout.widget.ConstraintLayout>
请注意以下几点:
在添加NavHostFragment的时候编译器并未对NavHostFragment的文件路径、defaultNavHost与navGraph属性进行智能提示。请你不要慌,不要怀疑是否有这些属性或值,坚定准确的把它敲完或复制粘贴成功!
android:name
属性包含 NavHost 实现的类名称。app:navGraph
属性将 NavHostFragment 与导航图相关联。导航图会在此 NavHostFragment 中指定用户可以导航到的所有目的地。app:defaultNavHost="true"
属性确保您的 NavHostFragment 会拦截系统返回按钮。请注意,只能有一个默认 NavHost。如果同一布局(例如,双窗格布局)中有多个主机,请务必仅指定一个默认 NavHost。
NavHostFragment 简单来讲就是一个导航界面容器,用来展示导航中一系列的 Fragment。
NavHostFragment在Activity布局文件中添加成功后,mobile_navigation.xml中navigation标签的红色警告消失了,取而代之的是一个黄色的提醒,这是由于我们并未在navigation的标签中添加一个“起始目的地"!即我们打开应用的第一张页面。在<navigation>
标签中添加上:
app:startDestination="@id/fragment_page_1_id"
此时在Navigation Edit中,作为起始目的地的Fragment顶部就会多了一个小房子。如下图所示:
这样我们创建好的Page1Fragment就会变成我们打开应用显示的第一个屏幕。
“起始目的地”配置好之后,我们需要为每一个fragment配置其的“目的地”。配置“目的地”的方式有两种,一种是在Navigation Edit中,拖拉可视化Fragment的箭头来指向它的“目的地”;第二种是直接在xml中,在每个Fragment中添加<action>
标签,并配置好其“目的地”。代码如下所示:
<?xml version="1.0" encoding="utf-8"?>
<navigation 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/mobile_navigation"app:startDestination="@id/fragment_page_1_id"><fragmentandroid:id="@+id/fragment_page_1_id"android:name="com.johnlion.navigation.Page1Fragment"android:label="fragment_page_1_label"tools:layout="@layout/fragment_page_1"><actionandroid:id="@+id/action_page_1_to_page_2"app:destination="@id/fragment_page_2_id" /></fragment><fragmentandroid:id="@+id/fragment_page_2_id"android:name="com.johnlion.navigation.Page2Fragment"android:label="fragment_page_2_label"tools:layout="@layout/fragment_page_2"><actionandroid:id="@+id/action_page_2_to_page_3"app:destination="@id/fragment_page_3_id" /><actionandroid:id="@+id/action_page_2_to_page_1"app:popUpTo="@id/fragment_page_1_id" /></fragment><fragmentandroid:id="@+id/fragment_page_3_id"android:name="com.johnlion.navigation.Page3Fragment"android:label="fragment_page_1_label"tools:layout="@layout/fragment_page_3"><actionandroid:id="@+id/action_page_3_to_page_2"app:popUpTo="@id/fragment_page_2_id" /></fragment></navigation>
应用导航图如下图所示:
实现跳转
接下来我们给每个Fragment配置好其对应的跳转事件。代码如下所示:
//第一个Fragment
class Page1Fragment : Fragment() {override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View? {return inflater.inflate(R.layout.fragment_page_1, container, false)}override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)btn_page1.setOnClickListener {Navigation.findNavController(it).navigate(R.id.action_page_1_to_page_2)}}
}
//第二个Fragment
class Page2Fragment : Fragment() {override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View? {return inflater.inflate(R.layout.fragment_page_2, container, false)}override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)btn_page2_1.setOnClickListener {Navigation.findNavController(it).navigateUp()}btn_page2_2.setOnClickListener {Navigation.findNavController(it).navigate(R.id.action_page_2_to_page_3)}}
}
//第三个Fragment
class Page3Fragment : Fragment() {override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View? {return inflater.inflate(R.layout.fragment_page_3, container, false)}override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)btn_page3.setOnClickListener {Navigation.findNavController(it).navigate(R.id.action_page_3_to_page_2)}}
}
从中我们可以看出Fragment之间的跳转用到的API为:
- Navigation.findNavController(view).navigate(actionID)。
- Navigation.findNavController(view).navigateUp()。
使用Bundle传递参数
代码如下所示:
btn_bundle.setOnClickListener {val bundle = Bundle()bundle.putString("key", "value")Navigation.findNavController(it).navigate(R.id.action_page_1_to_page_2, bundle)}
通过创建一个Bundle()
对象,把所要传递的key:value放进bundle里面,然后我们在的navigate(...)
方法中把bundle传进去,这样我们就可以通过bundle来实现参数的传递了。
界面切换动画
我们可以在目的地之间添加上动画的过渡效果,使Fragment与Fragment之前切换不生硬。那么我们来尝试做个右进左出的动画吧。
我们先创建所需要的xml文件,在res目录下新建一个anim文件夹,用来存放实现动画的xml文件,然后新建两个动画资源文件,起名为slide_in_right.xml
、slide_out_left.xml
,代码如下所示:
//slide_in_right.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"><translateandroid:duration="@android:integer/config_mediumAnimTime"android:fromXDelta="100%"android:interpolator="@android:anim/accelerate_interpolator"android:toXDelta="0" />
</set>//slide_out_left
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"><translateandroid:duration="@android:integer/config_mediumAnimTime"android:fromXDelta="0"android:interpolator="@android:anim/accelerate_interpolator"android:toXDelta="-100%"/>
</set>
添加动画文件完成之后我们可以通过两种方法来配置Fragment与Fragment之间跳转的动画过渡,一种是在导航中的<action>
标签下配置,另一种是通过代码中的navOptions
方法进行配置,动画配置代码如下所示:
//我们对一张Fragment跳转到第二张Fragment进行动画配置
//第一种:xml静态配置<actionandroid:id="@+id/action_page_1_to_page_2"app:destination="@id/fragment_page_2_id"app:enterAnim="@anim/slide_in_right"app:exitAnim="@anim/slide_out_left" />//第二种:代码动态配置val option = navOptions {anim {enter = R.anim.slide_in_rightexit = R.anim.slide_out_left}}btn_page1.setOnClickListener {Navigation.findNavController(it).navigate(R.id.action_page_1_to_page_2, null, option)}
在代码中配置需要注意:navigate(...)
中第一个参数传入的是actionID,第二个参数传入的是bundle对象,由于我们并没有新建一个bundle,所以选择传入null,第三个参数则是navOptions。
这样我们目的地与目的地之间的过渡动画就添加完成了~
到这里,通过运行预览,基本和示例一样效果了
使用 Safe Args 传递安全的数据
官方文档原话:
Navigation 组件具有一个名为 Safe Args 的 Gradle 插件,该插件可以生成简单的 object 和 builder 类,以便以类型安全的方式浏览和访问任何关联的参数。我们强烈建议您将 Safe Args 用于导航和数据传递,因为它可以确保类型安全。
先配置安全插件。
//顶级的build.gradlebuildscript {repositories {//...google()}dependencies {//...def nav_version = "2.1.0"classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"}}
//应用或模块级的build.gradle//...apply plugin: 'com.android.application'apply plugin: "androidx.navigation.safeargs.kotlin"android{//...kotlinOptions {jvmTarget = JavaVersion.VERSION_1_8} }
添加安全插件完成后,它会自动生成末尾带有Directions的类,该类的名称是在源目的地的名称后面加上“Directions”,该类里面带有原目的地action的方法。
在官方文档中介绍,Navigation 库支持以下参数类型:
那我们来挑上几种类型尝试一遍吧。
首先我们需要在mobile_navigation.xml中添加上我们自定义的参数,假如我们打算从Page1中把参数传递给Page2,那么我们则需要在Page2(接收目的地)的<fragment>
标签下添加上<argument>
标签并添加上名字、默认值、类型三种属性。代码如下所示:
<fragmentandroid:id="@+id/fragment_page_2_id"android:name="com.johnlion.navigation.Page2Fragment"android:label="fragment_page_2_label"tools:layout="@layout/fragment_page_2"><!--...--><argumentandroid:name="myInteger"android:defaultValue="0"app:argType="integer" /><argumentandroid:name="myString"android:defaultValue="value"app:argType="string" /><argumentandroid:name="myBoolean"android:defaultValue="false"app:argType="boolean" /></fragment>
添加完成后一定要reBuild一下项目,这样安全插件会为我们生成末尾带有“Args”的类,里面有我们接收参数目的地即Page2获取参数的方法。
而且在Page1FragemntDirections类中,用来实现action的方法在reBuild后会更新成传递三个默认参数给Page2接收。代码如下所示:
class Page1FragmentDirections private constructor() {//...companion object {fun actionPage1ToPage2(myInteger: Int = 0,myString: String = "value",myBoolean: Boolean = false): NavDirections = ActionPage1ToPage2(myInteger, myString, myBoolean)}
}
接下来我们看下如何在代码中传递安全的数据。代码如下所示:
//Page1Fragment(传递安全数据)
class Page1Fragment : Fragment() {//...override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)btn_page1.setOnClickListener {val action = Page1FragmentDirections.actionPage1ToPage2(1, "hello", true)Navigation.findNavController(it).navigate(action)}
}
//Page2Fragment(接收安全数据)
class Page2Fragment : Fragment() {val args: Page2FragmentArgs by navArgs()override fun onViewCreated(view: View, savedInstanceState: Bundle?) {//...//获取的参数名为<argument>中配置好的nameLog.d("data", "integer:" + args.myInteger)Log.d("data", "string:" + args.myString)Log.d("data", "boolean:" + args.myBoolean)}
}
如果我们在actionPage1ToPage2(...)
方法里什么都不加的话,就会把在xml设置好的android:defaultValue
传递过去。
从Page1传递Page2的参数要求不能为null,但如果参数类型支持 null 值,那么可以在<argument>
中,使用 android:defaultValue="@null"
和app:nullable="true"
结合声明默认值 null。
总的来讲,safe args给我的感觉就是,通过其用来传递数据,就是为了避免接收数据时会报空指针异常!
使用 NavigationUI 更新界面组件
导航架构组件包含 NavigationUI 类。此类包含使用顶部应用栏、抽屉式导航栏和底部导航栏管理导航的静态方法。
NavigationUI支持以下类型控件:
- Toolbar
- CollapsingToolbarLayout
- ActionBar
- DrawerLayout
- BottomNavigationView
我们选择BottomNavigationView结合Navigation做一个示例:
- 在res目录下下新建一个menu文件夹。
- 在menu文件夹中创建一个menu资源文件起名为:menu.xml。
- 在此文件中添加上如下代码:
注意:item中的id必须要与在mobile_navigation.xml中你要显示的Fragment id一致
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"><itemandroid:id="@+id/fragment_page_1_id"android:icon="@drawable/message"android:title="Page1" /><itemandroid:id="@+id/fragment_page_2_id"android:icon="@drawable/search"android:title="Page2" /><itemandroid:id="@+id/fragment_page_3_id"android:icon="@drawable/setting"android:title="Page3" />
</menu>
然后我们在Activity布局文件中添加BottomNavigationView控件,并把刚刚新创建好的menu文件关联其中。代码如下所示:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout ...><fragmentandroid:id="@+id/nav_host_fragment"... /><com.google.android.material.bottomnavigation.BottomNavigationViewandroid:id="@+id/bottom_navigation"android:layout_width="match_parent"android:layout_height="wrap_content"app:layout_constraintBottom_toBottomOf="parent"app:menu="@menu/menu" />
</androidx.constraintlayout.widget.ConstraintLayout>
最后我们在activity的代码中需要先把NavController给取出来,再把它传进BottomNavigationView中的setupWithNavController(...)
方法,而NavController是要在NavHostFragment里面取,所以第一步就是要把NavHostFragment找出来先,然后取出NavController,最后把它传递到setupWithNavController(...)
方法里就完成Navigation与BottomNavigationView的绑定了。代码如下所示:
class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val host: NavHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment? ?: returnval navController = host.navControllersetupBottomNavMenu(navController)}private fun setupBottomNavMenu(navController: NavController) {val bottomNav = findViewById<BottomNavigationView>(R.id.bottom_navigation)bottomNav?.setupWithNavController(navController)}
}
演示效果如下:
但是!看演示的效果会发现,我们依次点击BottomNavigationView上面的item,Page2 -> Page3,然后停留在Page3中点击真机上面的back按键则会先跳回到Page1,再点一次才退出应用,再试几遍才发现只要你不是停留在Page1中点击back按键都会先返回到Page1中,再点击一次back按键才退出应用。
我们要的效果是:只要点击BottomNavigation选择的Fragment,返回栈中只留它一个,再点击back按钮就可退出应用。
定位问题:
- 进入
bottomNav?.setupWithNavController(navController)
方法里。 - 发现里面只有一个
NavigationUI.setupWithNavController(this, navController)
方法,并进入该方法。 - 里面有一个对BottomNavigationView实现的监听
setOnNavigationItemSelectedListener
里返回了一个onNavDestinationSelected(item, navController);
,这个方法是用来关联Navigation与BottomNavigationView的MenuItem的。 - 问题就是出自这个方法里的
setPopUpTo(int destinationId, boolean inclusive)
,源码如下所示:
public static boolean onNavDestinationSelected(@NonNull MenuItem item,@NonNull NavController navController) {NavOptions.Builder builder = new NavOptions.Builder()//...if ((item.getOrder() & Menu.CATEGORY_SECONDARY) == 0) {builder.setPopUpTo(findStartDestination(navController.getGraph()).getId(), false);}NavOptions options = builder.build();try {navController.navigate(item.getItemId(), null, options);return true;} catch (IllegalArgumentException e) {return false;}}
当我们每次点击BottomNavigationView的Item的时候,都会走setPopUpTo(...)
方法,由于里面只指定“初始目的地”的id,所以每次都会弹出在其之上的目的地,且inclusive="false"
,这样“初始目的地”在栈中得到保留,并没有被移除!
这就是为什么:只要你不是停留在Page1中点击back按键都会先返回到Page1!
解决问题:
- 问题出自一个叫
onNavDestinationSelected(item, navController);
的方法里。 - 该方法里面只实现了导航跳转目的地,与设置跳转时的进出动画和目的地的启动模式。
- 此方法在BottomNavigationView的
setOnNavigationItemSelectedListener
监听里面。 - 该监听只实现
onNavDestinationSelected(item, navController)
一个方法!
那我们可以试着重写BottomNavigationView的setOnNavigationItemSelectedListener
监听,照着onNavDestinationSelected(...)
方法里面的内容,修改成我们需要的效果不就行了!
activity代码如下所示:
class MainActivity : AppCompatActivity() {//...private fun setupBottomNavMenu(navController: NavController) {val bottomNav = findViewById<BottomNavigationView>(R.id.bottom_navigation)bottomNav?.setupWithNavController(navController)//重写监听bottomNav.setOnNavigationItemSelectedListener { item: MenuItem ->val options = NavOptions.Builder()//从放回栈中移除指定目的地.setPopUpTo(navController.currentDestination!!.id, true).setLaunchSingleTop(true).build()try {//TODO provide proper API instead of using Exceptions as Control-Flow.navController.navigate(item.itemId, null, options)true} catch (e: IllegalArgumentException) {false}}}
}
演示效果如下:
完成!测试结果与我们想要的效果一致!
动态加载Navigation
先把Activity布局文件中的app:navGraph="@navigation/mobile_navigation"
去掉先。代码如下所示:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout ...><fragmentandroid:id="@+id/nav_host_fragment"android:name="androidx.navigation.fragment.NavHostFragment"android:layout_width="0dp"android:layout_height="0dp"app:defaultNavHost="true"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintLeft_toLeftOf="parent"app:layout_constraintRight_toRightOf="parent"app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
接着在Activity文件中,通过navController将Navigation的xml文件给inflater出来,并设置进navController的graph中。代码如下所示:
class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val host: NavHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment? ?: returnval navController = host.navControllerval navGraph: NavGraph =navController.navInflater.inflate(R.navigation.mobile_navigation)navController.graph = navGraph//...}//...
}
测试一遍,动态加载成功!
清空返回栈
假如我们打算从Page2跳到Page3时先把返回栈清空,然后跳转到Page3,这时返回栈应该就只有一个Page3的实例,当我们点击back’按键后,直接退出应用而不是放回Page2。
这是我在stackoverflow上找到了清空navigation返回栈的方法。
实现代码如下所示:
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"...><!--...--><fragmentandroid:id="@+id/fragment_page_2_id"...><actionandroid:id="@+id/action_page_2_to_page_3"app:destination="@id/fragment_page_3_id"app:launchSingleTop="true"app:popUpTo="@+id/mobile_navigation"app:popUpToInclusive="true" /><!--...--></fragment>
</navigation>
在Page2跳转到Page3的<action>
标签下添加上app:launchSingleTop="true"
、app:popUpTo="@+id/mobile_navigation"
和app:popUpToInclusive="true"
就能实现先清空放回栈然后跳转。
我们根据xml中添加的这些属性尝试在代码中实现。代码如下所示:
class Page2Fragment : Fragment() {//...override fun onViewCreated(view: View, savedInstanceState: Bundle?) {//...btn_page2_2.setOnClickListener {val navOption = NavOptions.Builder()//将xml中三个属性设置进去,就能实现先清栈后跳转.setLaunchSingleTop(true).setPopUpTo(R.id.mobile_navigation, true).build()Navigation.findNavController(it).navigate(R.id.action_page_2_to_page_3, null, navOption)}}
}
最后在Activity中实现一个全局清栈功能。
代码很简单,取出NavController,然后在调用navController.navigate(xxx)
方法前调用navController.popBackStack(R.id.mobile_navigation, true)
方法就能实现清栈。代码如下所示:
class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)val host: NavHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment? ?: returnval navController = host.navControllersetupBottomNavMenu(navController)}private fun clearStack(navController: NavController) {navController.popBackStack(R.id.mobile_navigation, true)}//...
}
当然“目的地”之间的跳转,应该统一放在activity里面管理,这里就不详细说明了。
只要拿到了navController,就能调用navController.navigate(xxx)
进行“目的地”跳转。
总结
Android JetPack推出的Navigation架构组件,用来作为构建应用内界面的框架,其重点是让单Activity应用成为首选架构。此控件处理了FragmentTransaction 的复杂性,并提供了帮助程序,用于将导航关联到合适的 UI 小部件,例如抽屉式导航栏和底部导航。
项目链接
示例:android-navigation
参考文章
- Android官方架构组件Navigation:大巧不工的Fragment管理框架
- Android Navigation Architecture Component 使用详解
- 官方文档
- 官方项目地址
- 官方项目教程
Android 官方架构组件 Navigation 使用详解相关推荐
- Android官方架构组件Paging:分页库的设计美学
本文已授权 微信公众号 玉刚说 (@任玉刚)独家发布. 2019/12/24 补充 距本文发布时隔一年,笔者认为,本文不应该作为入门教程的第一篇博客,相反,读者真正想要理解 Paging 的使用,应该 ...
- Android架构组件Room功能详解,面试必问
前言 在去年10月份的时候入职了一家外企,恰逢最近几周公司大规模招聘Android开发,有幸参与了十几场面试,遂有感而发.在其中也从面试官的方面有了一些想法,希望分享给大家. 本来当做面试官对于我来说 ...
- 字节跳动Android金三银四解析:Android架构组件Room功能详解,深度好文
前言 很多公司在招人这件事情上都会面临一个问题: "我们的招聘要求又不高,能做项目就行,但为什么就是招不到人?" 很多公司还面临一个问题,招聘的时候这人各方面都不错,但上岗了就是不 ...
- Android 开发架构-MVC MVP MVVM详解
何为架构 架构,即程序的逻辑组织结构,是指导开发过程中划分程序逻辑模块的关键,好的架构要使程序达到高内聚低耦合的设计目标.例如一个人,身体的骨骼即为身体的架构,有了基本骨架之后,才可以决定在头颅里开发 ...
- 安卓实例开发录音应用!Android架构组件Room功能详解,面试真题解析
越来越多的人在提"移动端的下半场"."Android 开发的焦虑"之类的,也有人在喊"技术天天在变,学也学不完","昨天 Kotl ...
- android lifecycle,Android 架构组件之 LifeCycle详解
1.Lifecycle介绍 为什么要使用lifecycle? activity 和fragment 是有声明周期的,有时候,我们的很多操作需要写在声明周期的方法中,比如,下载,文件操作等,这样很多情况 ...
- android官方架构room,Android 官方架构组件介绍之 Room(翻译)
持久库Room Room在SQLite上提供了一个抽象层,以便在利用SQLite的全部功能的同时使流畅的数据库访问. 需要处理一些重要的结构化数据的App通常会从本地的持久数据中受益匪浅.最常见的就是 ...
- android官方架构组件,Android 架构组件官方文档01——LifeCycle
使用生命周期感知组件处理生命周期 支持生命周期的组件执行操作以响应另一个组件(例如Activity和fragment)的生命周期状态更改.这些组件可帮助您生成组织性更好,并且通常更轻量的代码,这些代码 ...
- android 之四大组件的Activity详解
Activity的生命周期: Activity的四种基本状态: (1) 运行态(Running) Activity处在最前端,用户可见可获得焦点 (2) 暂停态(Paused) Activity处在最 ...
最新文章
- 从2019 AI顶会最佳论文,看深度学习的理论基础
- CListCtrl 使用技巧
- matlab向量的模_基于MATLAB使用矩阵方法求解一维定态薛定谔方程
- [python爬虫] BeautifulSoup和Selenium对比爬取豆瓣Top250电影信息
- 文件夹操作之判断是否存在(Directory)
- 数据级并行--计算机体系结构
- Activiti工作流框架学习(一)环境的搭建和数据表的了解
- 和dump文件什么区别_将java进程转移到“解剖台”之前,法医都干了什么?
- 用计算机的知识服务社会,科研育人案例-董立红
- HDU 1695 GCD ★(容斥原理+欧拉函数)
- python 实例化对象_python如何实例化对象
- 只有搞Java开发的才知道!javaspring菜鸟教程
- ICCV 2021 | FACIAL :动态谈话人脸视频生成,姿态,眨眼皆可控!
- qt中clicked()和toggled()的区别
- 腾讯云即时通信IM实现聊天功能
- java 调用软键盘_关于Java:可靠地隐藏软键盘
- 项目管理(PMP)项目进度管理
- 【自学python爬虫】:入门书籍推荐(附资源)
- 服务器虚拟系统无法上网络设置,玩转Windows 2008虚拟机网络设置
- SWUSTOJ #971 统计利用先序遍历创建的二叉树的深度
热门文章
- 盐湖卤水中分离硼的工艺有哪些
- 怎么向java窗口中插入XSL表_Java向word中插入Excel文件对象
- python绝技 pdf 中文_虫术Python绝技 PDF 完整版
- C# 联合KepServer对PLC进行数据读写
- 翻开下一页——离开,再开始
- oracle有的表带$,Oracle Update
- 支付宝摘下客服界的“奥斯卡”奖 支付宝的D+服务厉害在哪?
- 如何才能能够提升个人自信
- 1g2g3g4g5g_5g之路
- “百度杯”CTF比赛 2017 二月场,题目名称:爆破-3