软件编程
位置:首页>> 软件编程>> Android编程>> Jetpack navigation组件超详细讲解

Jetpack navigation组件超详细讲解

作者:幸大叔  发布时间:2021-07-17 08:49:58 

标签:Android,navigation,组件

导航是指支持用户导航、进入和退出应用中不同内容片段的交互。Android Jetpack 的导航组件可帮助您实现导航,无论是简单的按钮点击,还是应用栏和抽屉式导航栏等更为复杂的模式,该组件均可应对。导航组件还通过遵循一套既定原则来确保一致且可预测的用户体验。

依赖项

    def nav_version = "2.5.2"
    implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
    implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
    implementation "androidx.navigation:navigation-dynamic-features-fragment:$nav_version"

创建导航图

导航发生在应用中的各个目的地之间。这些目的地是通过操作连接的,导航图是一种资源文件,其中包含您的所有目的地和操作,该图表会显示应用的所有导航路径。

点击加号便可以创建目的地Fragment,连接操作由箭头表示,该箭头表示用户可以如何从一个目的地导航到另一个目的地。

Jetpack navigation组件超详细讲解

Jetpack navigation组件超详细讲解

目的地是指应用中的不同内容区域,操作是指目的地之间的逻辑连接,表示用户可以采取的路径。然后,我们来看下此时的导航xml代码::main_navigation.xml

<?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/main_navigation"
   app:startDestination="@id/oneFragment">
   <fragment
       android:id="@+id/oneFragment"
       android:name="com.example.myapplication.OneFragment"
       android:label="fragment_one"
       tools:layout="@layout/fragment_one" >
       <action
           android:id="@+id/action_oneFragment_to_twoFragment"
           app:destination="@id/twoFragment" />
   </fragment>
   <fragment
       android:id="@+id/twoFragment"
       android:name="com.example.myapplication.TwoFragment"
       android:label="fragment_two"
       tools:layout="@layout/fragment_two" >
       <action
           android:id="@+id/action_twoFragment_to_threeFragment"
           app:destination="@id/threeFragment" />
   </fragment>
   <fragment
       android:id="@+id/threeFragment"
       android:name="com.example.myapplication.ThreeFragment"
       android:label="fragment_three"
       tools:layout="@layout/fragment_three" />
</navigation>

其中,navigation 元素是导航图的根元素,当您向图表添加目的地和连接操作时,就 action 和 app:destination

导航宿主

导航宿主是一个空容器,用户在您的应用中导航时,目的地会在该容器中交换进出,导航宿主必须派生于 NavHost,Navigation 组件的默认 NavHost 实现 (NavHostFragment) 负责处理 Fragment 目的地的交换。

<?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"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context=".MainActivity">
   <androidx.fragment.app.FragmentContainerView
       android:id="@+id/container"
       android:name="androidx.navigation.fragment.NavHostFragment"
       android:layout_width="match_parent"
       android:layout_height="match_parent"
       app:defaultNavHost="true"
       app:navGraph="@navigation/main_navigation" />
</LinearLayout>

android:name:NavHost 实现类的名称

app:navGraph:将 NavHostFragment 与导航图相关联

app:defaultNavHost=&ldquo;true&rdquo;:确保 NavHostFragment 会拦截系统返回按钮。

注意:只能有一个默认 NavHost,如果同一布局(例如,双窗格布局)中有多个托管容器,请务必仅指定一个默认 NavHost

导航到目的地

跳转建议使用 Safe Args 确保类型安全,在 Project 下的 build.gradle 添加。启用 Safe Args 后,该插件会生成代码,其中包含每个操作的类和方法。对于每个操作,Safe Args 还会为每个源头生成一个类。生成的类的名称由源类的名称和&ldquo;Directions&rdquo;一词组成,例如OneFragment,生成的就是OneFragmentDirections

buildscript {
    repositories {
        google()
    }
    dependencies {
        def nav_version = "2.5.2"
        classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
    }
}

在APP模块的 build.gradle 添加

plugins {
    id 'androidx.navigation.safeargs'
}

点击按钮,进行跳转

jump.setOnClickListener {
           val action = OneFragmentDirections.actionOneFragmentToTwoFragment()
           it.findNavController().navigate(action)
       }

传递参数

启用 Safe Args 后,会创建一个类,该类的名称是在目的地的名称后面加上&ldquo;Args&rdquo;,例如 OneFragment,名称为OneFragmentArgs,用于参数传递。

在 main_navigation.xml 加上参数标签 argument

<fragment
       android:id="@+id/oneFragment"
       android:name="com.example.myapplication.OneFragment"
       android:label="fragment_one"
       tools:layout="@layout/fragment_one">
       <argument
           android:name="name"
           android:defaultValue="1"
           app:argType="string" />
       <action
           android:id="@+id/action_oneFragment_to_twoFragment"
           app:destination="@id/twoFragment" />
   </fragment>

在 OneFragment 中进行跳转,参数传递

jump.setOnClickListener {
           val param = OneFragmentArgs.Builder().setName(nameStr).build().toBundle()
           it.findNavController().navigate(R.id.action_oneFragment_to_twoFragment, param)
       }

TwoFragment接收参数,建议使用 ktx,就可以使用 by navArgs() 属性委托来访问参数

class TwoFragment : Fragment() {
   private val args: OneFragmentArgs by navArgs()
   override fun onCreateView(
       inflater: LayoutInflater, container: ViewGroup?,
       savedInstanceState: Bundle?
   ): View? {
       val nameStr = args.name //接收的值
       return inflater.inflate(R.layout.fragment_two, container, false)
   }
}

NavigationUI

此类包含多种静态方法,可帮助您使用顶部应用栏、抽屉式导航栏和底部导航栏来管理导航。

这里简单实现一个底部导航栏,先创建一个menu

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
   <item
       android:id="@+id/oneFragment"
       android:icon="@android:drawable/ic_menu_camera"
       android:title="相机" />
   <item
       android:id="@+id/twoFragment"
       android:icon="@android:drawable/ic_dialog_email"
       android:title="邮件" />
   <item
       android:id="@+id/threeFragment"
       android:icon="@android:drawable/ic_menu_call"
       android:title="电话" />
</menu>

创建三个Fragment,OneFragment,TwoFragment 和 ThreeFragment,作为三个页面

然后 navigation 长这样,需要注意的是menu各个item的id和fragment的id需要相对应

<?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/main_navigation"
   app:startDestination="@id/oneFragment">
   <fragment
       android:id="@+id/oneFragment"
       android:name="com.example.myapplication.OneFragment"
       android:label="fragment_one"
       tools:layout="@layout/fragment_one" />
   <fragment
       android:id="@+id/twoFragment"
       android:name="com.example.myapplication.TwoFragment"
       android:label="fragment_two"
       tools:layout="@layout/fragment_two" />
   <fragment
       android:id="@+id/threeFragment"
       android:name="com.example.myapplication.ThreeFragment"
       android:label="fragment_three"
       tools:layout="@layout/fragment_three" />
</navigation>

宿主的布局如下

<?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"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   android:orientation="vertical"
   tools:context=".MainActivity">
   <androidx.fragment.app.FragmentContainerView
       android:id="@+id/container"
       android:name="androidx.navigation.fragment.NavHostFragment"
       android:layout_width="match_parent"
       android:layout_height="0dp"
       android:layout_weight="1"
       app:defaultNavHost="true"
       app:navGraph="@navigation/main_navigation" />
   <com.google.android.material.bottomnavigation.BottomNavigationView
       android:id="@+id/bottom"
       android:layout_width="match_parent"
       android:layout_height="wrap_content"
       app:menu="@menu/main_item" />
</LinearLayout>

然后在宿主Activity中执行如下就行啦

val navHostFragment =
           supportFragmentManager.findFragmentById(R.id.container) as NavHostFragment
       val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottom)
       NavigationUI.setupWithNavController(bottomNavigationView, navHostFragment.navController)

Jetpack navigation组件超详细讲解

多模块导航

对于比较大型的项目,我们一般都会采用组件化开发,每个功能模块都专注于一项功能。每个功能模块都是一个独立的单元,拥有自己的导航图和目的地,app 模块依赖于每个功能模块。

app 模块负责提供应用的完整导航图,以及将 NavHost 添加到界面中,可以使用 include 来引用库图。

<?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/main_navigation"
   app:startDestination="@id/mainFragment">
   <include app:graph="@navigation/bike_nav" />
   <include app:graph="@navigation/car_nav" />
   <fragment
       android:id="@+id/mainFragment"
       android:name="com.example.myapplication.MainFragment"
       android:label="fragment_main"
       tools:layout="@layout/fragment_main">
       <action
           android:id="@+id/action_mainFragment_to_car_nav"
           app:destination="@id/car_nav" />
       <action
           android:id="@+id/action_mainFragment_to_bike_nav"
           app:destination="@id/bike_nav" />
   </fragment>
</navigation>

如下图所示,这里主页面一个MainFragment,用来做跳转,分别可跳转到两个不同的模块

Jetpack navigation组件超详细讲解

然后在 MainFragment 里执行跳转逻辑

findViewById<TextView>(R.id.red).setOnClickListener {
               it.findNavController().navigate(MainFragmentDirections.actionMainFragmentToCarNav())
           }
           findViewById<TextView>(R.id.purple).setOnClickListener {
               it.findNavController()
                   .navigate(MainFragmentDirections.actionMainFragmentToBikeNav())
           }

Jetpack navigation组件超详细讲解

那么,问题来了,如果是两个单独的功能模块之间需要导航呢,而独立的功能模块彼此又看不到对方,怎么搞呢?

这时,可以使用深层链接直接导航到与隐式深层链接关联的目的地

举个例子,现在要从 Bikelibrary 里的 Fragment 跳转到 Carlibrary 里的 Fragment

Jetpack navigation组件超详细讲解

将 Carlibrary 中的导航添加深层链接

<?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/car_nav"
   app:startDestination="@id/carFragment">
   <fragment
       android:id="@+id/carFragment"
       android:name="com.example.carlibrary.CarFragment"
       android:label="fragment_car"
       tools:layout="@layout/fragment_car">
       <deepLink
           android:id="@+id/deepLink"
           app:uri="android-app://com.example.carlibrary/carFragment" />
   </fragment>
</navigation>

当然,你也可以从xml编辑器的右侧添加

Jetpack navigation组件超详细讲解

然后在 bikelibrary 里的 fragment 中根据此链接进行导航,这里设置了一个按钮的点击事件

findViewById<Button>(R.id.bike_to_car).setOnClickListener {
               val request =
                   NavDeepLinkRequest.Builder.fromUri("android-app://com.example.carlibrary/carFragment".toUri())
                       .build()
               it.findNavController().navigate(request)
           }

这样,就完成了跨模块导航,是不是很方便呢?不过,需要注意的是,Safe Args 不支持跨模块导航,因为没有针对目的地的直接操作。

来源:https://blog.csdn.net/qq_45485851/article/details/127556505

0
投稿

猜你喜欢

  • 混淆器通过删除从未用过的代码和使用晦涩名字重命名类、字段和方法,对代码进行压缩,优化和混淆。结果是一个比較小的.apk文件,该文件比較难进行
  • 一、项目简述本系统功能包括: 一款基于Springboot+Vue的电商项目,前后端分离项目,前台后台都有,前台商品展示购买,购物车分类,订
  • 倒序拼接字符串@ApiOperation("分页查询")    @GetMapping(value
  • 一、什么是重量级锁当有大量的线程都在竞争同一把锁的时候,这个时候加的锁,就是重量级锁。这个重量级锁其实指的就是JVM内部的ObjectMon
  • 背景由于前前前阵子写了个壳,得去了解类的加载流程,当时记了一些潦草的笔记。这几天把这些东西简单梳理了一下,本文分析的代码基于Android8
  • java的接口解耦方式我只想把抽象的东西说的具体,或者说,听起来简单些,明白些。。。学过java的人都知道,java是单继承的,也就是说一个
  • 要点1:cmd命令行的输入命令netsh wlan set hostednetwork mode=allow ssid=用户名 
  • 使用淘宝ip地址库的api查询ip地址信息。TaobaoIPHelper.csusing System;using System.Coll
  • 本文以实例形式详细讲述了Java的反射机制,是Java程序设计中重要的技巧。分享给大家供大家参考。具体分析如下:首先,Reflection是
  • 下面给大家介绍下mybatis结果生成键值对的实例代码,具体内容如下所示:在实际应用中我们经常会遇到这样的情况,需要给下拉框赋值,这个时候就
  • 布尔表达式:布尔表达式(Boolean expression)是一段代码声明,它最终只有true(真)和false(假)两个取值。最简单的布
  • 微软Office Word本身已经提供了另存为PDF文档功能,对于少量文档,手工使用该方式进行Word转换为PDF尚可,一旦需要处理大量的文
  • 本文介绍了最好的Java5种遍历HashMap数据的写法,分享给大家,也给自己留一个笔记,具体如下:通过EntrySet的迭代器遍历Iter
  • 本文实例为大家分享了Flutter实现顶部导航栏的具体代码,供大家参考,具体内容如下import 'package:flutter/
  • 好问题。答案就是这篇文章的题目所建议的,这是一种合理的设计。在这种情况下,newInstance()方法是一种“静态工厂方法",让
  • 目录创建线程管理线程销毁线程创建线程线程是通过扩展 Thread 类创建的。扩展的 Thread 类调用 Start() 方法来开
  • 在使用SpringSecurity中,大伙都知道默认的登录数据是通过key/value的形式来传递的,默认情况下不支持JSON格式的登录数据
  • 前言EventBus框架EventBus是一个通用的叫法,例如Google出品的Guava,Guava是一个庞大的库,EventBus只是它
  • 简述增量更新,根据字面理解,就是下载增加的那部分来达到更新的目的,实际就是这个意思。原理用一个旧的Apk安装与一个新的Apk安装包使用 bs
  • 迅雷下载是目前使用非常普遍的一个下载软件,本文实例展示了C#实现调用迅雷下载的方法。具体方法如下:目前该实例代码只支持HTTP协议,具体功能
手机版 软件编程 asp之家 www.aspxhome.com