androidjetpack导航组件——navigation的使用(代码片段)

我就是马云飞 我就是马云飞     2022-11-02     518

关键词:

概述

Navigation是采用一个Activity和多个Fragment形式设计的Ui架构模式,但是众所周知,Fragment的管理一直是个麻烦事,需要通过FragmentManager和FragmentTransaction来管理Fragment之间的切换。所以Google提供了一套Navigation用来管理Fragment相互间的跳转等逻辑。我们先看下Navigation的优势:

  • 处理 Fragment 事务。

  • 默认情况下,正确处理往返操作。

  • 为动画和转换提供标准化资源。

  • 实现和处理深层链接。

  • 包括导航界面模式(例如抽屉式导航栏和底部导航),用户只需完成极少的额外工作。

  • Safe Args - 可在目标之间导航和传递数据时提供类型安全的 Gradle 插件。

  • ViewModel支持 - 您可以将ViewModel的范围限定为导航图,以在图表的目标之间共享与界面相关的数据。

正式介绍前,我们需要了解Navigation是由哪几部分组成的,现在我们看一下:

  • NavHostFragment:一种特殊的Fragment,用于承载导航内容的容器。

  • Navigation Graph:一个包含所有导航和页面关系相关的 XML资源。

  • NavController:管理应用导航的对象,实现Fragment之间的跳转等操作。

Navigation使用

Navigation Graph

首先我们在build.gradle 文件中新增navigation的依赖:

    // Kotlin
    implementation("androidx.navigation:navigation-fragment-ktx:$lifecycle_version") 
    implementation("androidx.navigation:navigation-ui-ktx:$lifecycle_version") 

然后我们需要新建一个Navigation,点击Project->Res->New Android Resource File,Resource Type选择Navigation,如下图:

打开新建的nav_graph.xml文件,在Design界面可以看到目前还没有内容,可以依次点击[New Destination]图标,然后点击[Create new destination],即可快速创建新的Fragment,这里作次示例,因为本身之前我已经新建好多个Fragment了,就不单独示范了。

我们可以点击视图的小圆点,建议页面的绑定关系。我这里已经建立好多个页面的绑定关系,同时你可以切换至code模块,本人代码如下:

<?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/jetpack_nav"
    app:startDestination="@id/navigationFragment">

    <fragment
        android:id="@+id/navigationFragment"
        android:name="com.silence.apmprojetct.NavigationFragment"
        android:label="fragment_navigation"
        tools:layout="@layout/fragment_navigation">
        <action
            android:id="@+id/action_navigationFragment_to_blankFragment"
            app:destination="@id/blankFragment" />
        <action
            android:id="@+id/action_navigationFragment_to_threeFragment"
            app:destination="@+id/threeFragment" />
    </fragment>
    <fragment
        android:id="@+id/blankFragment"
        android:name="com.silence.apmprojetct.SecondFragment"
        android:label="fragment_blank"
        tools:layout="@layout/fragment_second">
        <action
            android:id="@+id/action_blankFragment_to_threeFragment"
            app:destination="@id/threeFragment" />
    </fragment>
    <fragment
        android:id="@+id/threeFragment"
        android:name="com.silence.apmprojetct.ThreeFragment"
        android:label="fragment_three"
        tools:layout="@layout/fragment_three">
        <action
            android:id="@+id/action_threeFragment_to_navigationFragment"
            app:destination="@+id/navigationFragment"
            app:enterAnim="@anim/nav_default_enter_anim"
            app:exitAnim="@anim/nav_default_exit_anim"
            app:popEnterAnim="@anim/nav_default_pop_enter_anim"
            app:popExitAnim="@anim/nav_default_pop_exit_anim" />
    </fragment>
</navigation>

我们看下几个标签的含义:

  • navigation:根标签,通过startDestination配置指定默认的启动页面。
  • fragment: fragment标签代表一个fragment。
  • action:action标签定义了页面跳转的行为,destination标签定义跳转的目标页,里面还有启动模式的相关设置等等。

NavHostFragment

而讲到这里,我们只概括前面三个模块其中之一Navigation Graph。我们知道Fragment需要一个Activity才能正常运行,但是我们如何在我们的Activity指定我们上面startDestination呢。这就需要用到了NavHostFragment。我们看下我们Activity的布局代码:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    tools:context=".NavigationActivity">
    <fragment
        android:id="@+id/fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/jetpack_nav" />

</FrameLayout>

我们可以看到布局里定义了一个Fragment,并且它使用的就是NavHostFragment,可以看到navGraph属性绑定了我们刚刚写的Navigation文件。而defaultNavHost就是做到了自动实现了页面间的返回操作。如果没有这个属性,点击返回的时候就是直接关闭当前Activity了。当然,其内部Fragment的点击事件我们可以自己控制。

然后我们可以运行程序,可以看到默认展示的是NavigationFragment页面,这是因为NavigationActivity的布局文件中配置了NavHostFragment,并且给NavHostFragment指定了默认展示的页面为NavigationFragment。

NavController

NavController主要用来管理fragment之间的跳转,每个NavHost均有自己的相应NavController。然后可以使用它的navigate或者navigateUp方法来进行页面之间的路由操作。比如我这边的NavigationFragment需要跳转SecondFragment。我们可以这么写:

 override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? 
        val view = inflater.inflate(R.layout.fragment_navigation, container, false)
        view.findViewById<TextView>(R.id.next).setOnClickListener 
            findNavController().navigate(R.id.action_navigationFragment_to_blankFragment)
        
        return view
    

也就是通过navigate指向前面我们在action定义的id。即可完成跳转。

参数传递

Bundle数据传递

我们可以创建一个Bundle对象,然后使用navigate()将它传递给目的地,代码如下:

        val bundle = Bundle()
        bundle.putString(TITLE, getString(R.string.three_fragment_navigation_bundle_label))
        findNavController().navigate(R.id.action_blankFragment_to_threeFragment, bundle)

使用 Safe Args 传递安全的数据

这是官方为了navigation数据传递安全提供的一个数据传递方式,首先我们需要在根目录的build.gradle文件中添加如下依赖:

 dependencies 
        def nav_version = "2.3.3"
        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
    

然后我们在模块的build.gradle文件中新增如下:

//kotlin
apply plugin: "androidx.navigation.safeargs.kotlin"
//java
apply plugin: 'androidx.navigation.safeargs'

然后我们ReBuild项目,可以看到在build目录中生成了如下文件:

然后我们修改我们的代码,比如我需要在ThreeFragment页面新增一个参数,那么我们需要在navigation文件中新增如下代码:

<fragment
        android:id="@+id/threeFragment"
        android:name="com.silence.apmprojetct.ThreeFragment"
        android:label="fragment_three"
        tools:layout="@layout/fragment_three">
        <action
            android:id="@+id/action_threeFragment_to_navigationFragment"
            app:destination="@+id/navigationFragment" />
        <argument
            android:name="key"
            app:argType="string"
            android:defaultValue="safeArgs" />
    </fragment>

然后我们在需要跳转的时候修改下代码,比如我这里SecondFragment会跳转至ThreeFragment。那么我们只需要这么写:

        view.findViewById<TextView>(R.id.next).setOnClickListener 
//            val bundle = Bundle()
//            bundle.putString(TITLE, getString(R.string.three_fragment_navigation_bundle_label))
//            findNavController().navigate(R.id.action_blankFragment_to_threeFragment, bundle)
            var secondFragment =
                SecondFragmentDirections.actionBlankFragmentToThreeFragment("safe传递的数据")
            findNavController().navigate(secondFragment)
        

我们在看下如何在ThreeFragment里接收数据:

 view.findViewById<TextView>(R.id.title).text = arguments?.let 
            ThreeFragmentArgs.fromBundle(it).key
        

其他场景

堆栈处理

前面我们说到了正常的页面启动,以及如何挟带参数跳转。现在有个场景,比如我A-》B-》C之后,然后直接回到A。并且清栈,也就是在A页面返回就直接关闭当前的Activity了。我们看一下,目前我们的代码执行后效果会如何:

可以看出来我们每次打开新的fragment就相当于新开了一个堆栈。我们可记得我们配置页面的时候有一个action属性。我们把action的代码改成如下:

 <fragment
        android:id="@+id/threeFragment"
        android:name="com.silence.apmprojetct.ThreeFragment"
        android:label="fragment_three"
        tools:layout="@layout/fragment_three">
        <action
            android:id="@+id/action_threeFragment_to_navigationFragment"
            app:destination="@+id/navigationFragment"
            app:popUpTo="@+id/navigationFragment"
            app:popUpToInclusive="true" />
    </fragment>

我们运行一下,在看一下效果:

哎,可以了。

其实action还有一个属性launchSingleTop的设置,这个看具体场景使用即可。

指定startDestination

我们想一下,如何指定startDestination的Fragment呢。上面介绍过,activity要绑定NavHostFragment。而NavHostFragment要指定startDestination。在我们在navigaiton指定了fragment后,可以修改么。或者说,我可以动态改变他的startDestination嘛。其实是可以的。我们知道startDestination是由navGraph指定的。那么我们只需要修改activity的代码,就可以做到了。具体示例如下:

 override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_navigation)
        val startDestinationID = R.id.blankFragment
        val navController = Navigation.findNavController(this, R.id.fragment)
        val navInflater = navController.navInflater
        val navGraph = navInflater.inflate(R.navigation.jetpack_nav)
        navGraph.startDestination = startDestinationID
        navController.graph = navGraph
    

那我们执行一下,看下效果:

我这边指定了SecondFragment成功了。那具体指定哪一个,由你自己的业务场景而定。

总结

本文我们主要介绍了Jetpack中的导航组件Navigation的组件,从普通的跳转,已经挟带参数跳转,甚至一些特殊场景的跳转逻辑。关于一些其他场景,我这里不过多介绍,因为目前正常的跳转场景基本已经了解了。如果你想知道更多的使用场景,请查看官方文档

本文首发于我的个人博客:Android Jetpack导航组件——Navigation的使用

更多文章请关注我的公众号:码农职场

androidjetpack-使用navigation管理页面跳转(代码片段)

在今年的IO大会上,发布了一套叫AndroidJetpack的程序库。AndroidJetpack里的组件大部分我们都接触过了,其中也有一些全新的组件,其中一个就是Navigation。简介Navigation是用来管理APP里页面跳转的。起初,我以为它是用来代替startActiv... 查看详情

jetpack学习-navigation(代码片段)

...支持用户导航、进入和退出应用中不同内容片段的交互。AndroidJetpack的导航组件可帮助您实现导航,无论是简单的按钮点击,还是应用栏和抽屉式导航栏等更为复杂的模式,该组件均可应对。导航组件还通过遵循一套既定原则来... 查看详情

官方架构组件navigation管理fragment框架(代码片段)

...使用kotlin语言特性时,可以让你更有效率。消除样板代码AndroidJetpack管理乏味的活动,例如后台任务、导航和生命周期管理,你可以专注于让你的app更棒的东西。构建高质量、健壮的app基于现代设计实践,AndroidJetpack组件可以减... 查看详情

androidjetpack之navigation源码分析(代码片段)

AndroidJetpack之Navigation源码分析AndroidNavigation简介关于Fragment的基础篇:Fragment基础篇官方指导地址:官方指地址Githubdemo地址:demo使用Navigation可以管理APP页面跳转。Navigation不部分情况下作用于Fragment中,使用Navigation... 查看详情

使用 React Navigation 导航堆栈时重新渲染组件

】使用ReactNavigation导航堆栈时重新渲染组件【英文标题】:Re-rendercomponentwhennavigatingthestackwithReactNavigation【发布时间】:2019-03-1905:46:31【问题描述】:我目前正在使用react-navigation进行堆栈和选项卡导航。是否可以在用户每次导航... 查看详情

React Native Navigation:从 React 组件外部导航到屏幕

】ReactNativeNavigation:从React组件外部导航到屏幕【英文标题】:ReactNativeNavigation:NavigatetoascreenfromoutsideaReactcomponent【发布时间】:2021-08-1914:08:21【问题描述】:https://wix.github.io/react-native-navigation/docs/basic-navigation#navigating 查看详情

Android Navigation 组件在图表之间导航

】AndroidNavigation组件在图表之间导航【英文标题】:AndroidNavigationComponentnavigatebetweengraphs【发布时间】:2020-01-1508:56:07【问题描述】:我有两个导航图nav_graph_red和nav_graph_blue以及两个活动ActivityRed和ActivityBlue。在每个导航图中,我... 查看详情

导航编辑器初始化失败

...-03-2502:26:10【问题描述】:突然,AndroidStudio开始提示使用AndroidJetpack的Navigation需要安装一个模块android.arch.navigation:navigation-fragment:+.。这是整个模块名称。两个问题。第一,我已经安装了它,版本1.0.0al 查看详情

Android Jetpack Navigation - 如何从抽屉菜单项导航到嵌套导航图

】AndroidJetpackNavigation-如何从抽屉菜单项导航到嵌套导航图【英文标题】:AndroidJetpackNavigation-Howtonavigatetonestednavgraphfromdrawermenuitem【发布时间】:2020-07-0516:29:09【问题描述】:我很好奇如何使用AndroidJetpack的导航图从抽屉布局中的... 查看详情

如何通过 React Navigation 将导航道具传入功能组件屏幕?

】如何通过ReactNavigation将导航道具传入功能组件屏幕?【英文标题】:HowtopassinnavigationpropsintoafunctionalcomponentscreenthroughReactNavigation?【发布时间】:2020-08-2900:33:48【问题描述】:我有一个带有自定义“任务”的ReactNativeFlatList的功... 查看详情

android jetpack 导航仪器测试在返回导航上失败

】androidjetpack导航仪器测试在返回导航上失败【英文标题】:androidjetpacknavigationinstrumentedtestfailonbacknavigation【发布时间】:2021-06-1023:02:01【问题描述】:我使用jetpackNavigation组件(androidx.navigation)创建了一个简单的两个片段示例应... 查看详情

TypeError:未定义不是对象(评估“navigation.navigate”),无法从放置在屏幕上的组件导航到另一个屏幕

...评估“navigation.navigate”),无法从放置在屏幕上的组件导航到另一个屏幕【英文标题】:TypeError:undefinedisnotanobject(evaluating\'navigation.navigate\'),cannotnavigatefromcomponentplacedonscreentoanotherscreen【发布时间】:2021-11-0923:03:13 查看详情

reactnative导航器之react-navigation使用

在上一节Navigation组件,我们使用系统提供的导航组件做了一个跳转的例子,不过其实战能力不强,这里推荐一个超牛逼的第三方库:react-navigation。在讲react-navigation之前,我们先看一下常用的导航组件。导航控件常见的导航主要... 查看详情

如何将道具传递给 React Navigation 导航器中的组件?

】如何将道具传递给ReactNavigation导航器中的组件?【英文标题】:HowtopasspropstocomponentinsideaReactNavigationnavigator?【发布时间】:2018-10-3002:56:39【问题描述】:我正在尝试将props传递给已通过调用create...Navigator调用包装的组件,即//Se... 查看详情

navigation导航组件的使用:内容承载容器navhostfragment加载原理(代码片段)

Navigation导航组件由以下三个关键部分组成:导航图:在一个集中的位置包含所有与导航相关的信息的XML资源。这包括应用程序中所有单独的内容区域,称为目的地,以及用户可以在应用程序中使用的可能路径。Nav... 查看详情

v2 Navigation.showModal 创建新组件实例但实际上并未导航到它

】v2Navigation.showModal创建新组件实例但实际上并未导航到它【英文标题】:v2Navigation.showModalcreatingnewcomponentinstancebutnotactuallynavigatingtoit【发布时间】:2019-06-2609:08:41【问题描述】:我正在尝试使用react-native-navigationv2(版本2.8.0)... 查看详情

是否可以使用 Android 导航架构组件(Android Jetpack)有条件地设置 startDestination?

】是否可以使用Android导航架构组件(AndroidJetpack)有条件地设置startDestination?【英文标题】:IsitpossibletosetstartDestinationconditionallyusingAndroidNavigationArchitectureComponent(AndroidJetpack)?【发布时间】:2019-01-2611:56:27【问题描述】:我正在... 查看详情

react-native中导航组件react-navigation的使用(代码片段)

...头的话最近使用React-Native开发新应用,一开始使用的导航器是navigator,后来发现navigator有很多不足之处,而且官方也建议使用react-navigation来进行开发,所以现在转为使用react-navigation开发新应用了。总览ReactNative中... 查看详情