【Android Jetpack】Navigation的使用

引入

单个Activity嵌套多个Fragment的UI架构模式,非常非常普遍。但是,对Fragment的管理一直是一件比较麻烦的事情。工程师需要通过FragmentManagerFragmentTransaction来管理Fragment之间的切换。页面的切换通常还包括对应用程序App bar的管理、Fragment间的切换动画,以及Fragment间的参数传递。纯代码的方式使用起来不是特别友好,并且Fragment和App bar在管理和使用的过程中显得很混乱。

为此,Jetpack提供了一个名为Navigation的组件,旨在方便我们管理页面和App bar。

Navigation具有以下优势:

  • 可视化的页面导航图,类似于Apple Xcode中的StoryBoard,便于我们理清页面间的关系。
  • 通过destination和action完成页面间的导航。
  • 方便添加页面切换动画。
  • 页面间类型安全的参数传递。
  • 通过NavigationUI类,对菜单、底部导航、抽屉菜单导航进行统一的管理。
  • 支持深层链接DeepLink。

Navigation 组件旨在用于具有一个主 Activity 和多个 Fragment 目的地的应用。主 Activity 与导航图相关联,且包含一个负责根据需要交换目的地的 NavHostFragment。在具有多个 Activity 目的地的应用中,每个 Activity 均拥有其自己的导航图。

主要元素

导航组件由以下三个关键部分组成:

  1. Navigation Graph

    在一个集中位置包含所有导航相关信息的 XML 资源。这包括应用内所有单个内容区域(称为目标)以及用户可以通过应用获取的可能路径。

  2. NavHost

    显示导航图中目标的空白容器。导航组件包含一个默认NavHost实现 (NavHostFragment),可显示Fragment目标。

  3. NavController

    在NavHost中管理应用导航的对象。当用户在整个应用中移动时,NavController会安排NavHost中目标内容的交换。

在应用中导航时,您告诉NavController,您想沿导航图中的特定路径导航至特定目标,或直接导航至特定目标。NavController便会在NavHost中显示相应目标。

例如利用 BottomNavigationView + Fragment/FragmentContainerView 的组合实现底部导航栏

    <com.google.android.material.bottomnavigation.BottomNavigationView
        android:id="@+id/btmnv"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:background="@drawable/jianbian0"
        app:itemRippleColor="@color/colorDeep"
        app:itemIconTint="@drawable/btmnv_select"
        app:itemTextColor="@drawable/btmnv_select"
        app:menu="@menu/btmnvmenu"
        app:labelVisibilityMode="selected"
        app:itemBackground="@null"
        />

    <androidx.fragment.app.FragmentContainerView
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/mobile_navigation" />

代码:

         val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
         binding.btmnv.setupWithNavController(navHostFragment.navController)

Navigation Graph

导航图是一种资源文件,其中包含您的所有目的地和操作。该图表会显示应用的所有导航路径。

向项目添加导航图:

image-20231108003450382

<?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"
            android:id="@+id/nav_graph">
</navigation>

<navigation> 元素是导航图的根元素。当您向图表添加目的地和连接操作时,可以看到相应的 <destination><action> 元素在此处显示为子元素。如果您有,它们将显示为子 <navigation> 元素。

向 Activity 添加 NavHost

导航宿主是 Navigation 组件的核心部分之一。导航宿主是一个空容器,用户在您的应用中导航时,目的地会在该容器中交换进出。

导航宿主必须派生于 NavHost。Navigation 组件的默认 NavHost 实现 (NavHostFragment) 负责处理 Fragment 的更换。

静态添加

   <androidx.fragment.app.FragmentContainerView
        .....
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph" />

NavHostFragment是一个特殊的Fragment(android:name所定义的),我们需要将其添加到Activity的布局文件中,作为其他Fragment的容器,然后定义Fragment。

  • android:name :包含 NavHost 实现的类名称。
  • app:navGraph :将 NavHostFragment导航图相关联。导航图会在此 NavHostFragment 中指定用户可以浏览的碎片。
  • app:defaultNavHost="true" :确保您的 NavHostFragment 会自动处理系统返回键,即当用户按下手机的返回按钮时,系统能自动将当前所展示的Fragment退出。并且只能有一个默认 NavHost
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:android="http://schemas.android.com/apk/res/android"
    app:startDestination="@id/theFirstFragment"> // 最开始所展示的Fragment
    <fragment
        android:id="@+id/theFirstFragment"
        ...... />
</navigation>

导航到目的地

导航到目的地是使用 NavController 完成的,它是一个在 NavHost 中管理应用导航的对象。每个 NavHost 均有自己的相应 NavController。您可以使用以下方法之一检索 NavController

Kotlin

  • Fragment.findNavController()
  • View.findNavController()
  • Activity.findNavController(viewId: Int)

Java

  • NavHostFragment.findNavController(Fragment)
  • [Navigation.findNavController(Activity, @IdRes int viewId)](https://developer.android.com/reference/androidx/navigation/Navigation#findNavController(android.app.Activity, int))
  • Navigation.findNavController(View)

使用 FragmentContainerView 创建 NavHostFragment,或通过 FragmentTransaction 手动将 NavHostFragment 添加到您的 Activity 时,尝试通过 Navigation.findNavController(Activity, @IdRes int) 检索 Activity 的 onCreate() 中的 NavController 将失败。您应改为直接从 NavHostFragment 检索 NavController。(没用过,不清楚,搬得)

val navHostFragment =
        supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
val navController = navHostFragment.navController
navController.navigate(R.id.action_blankFragment_to_blankFragment2)

对于按钮,您还可以使用 Navigation 类的 createNavigateOnClickListener() 便捷方法导航到目的地,如下例所示:

button.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.theAimFragment, null))

使用 DeepLinkRequest 导航

您可以使用 navigate(NavDeepLinkRequest) 直接导航到隐式深层链接目的地,如下例所示:

val request = NavDeepLinkRequest.Builder
    .fromUri("android-app://androidx.navigation.app/profile".toUri())
    .build()
findNavController().navigate(request)

返回堆栈

Android 会维护一个返回堆栈,其中包含您之前访问过的目的地。当用户打开应用时,应用的第一个目的地就放置在堆栈中。每次调用 navigate() 方法都会将另一目的地放置到堆栈的顶部。点按向上返回会分别调用 NavController.navigateUp()NavController.popBackStack() 方法,用于移除(或弹出)堆栈顶部的目的地。

NavController.popBackStack() 会返回一个布尔值,表明它是否已成功返回到另一个目的地。当返回 false 时,最常见的情况是手动弹出图的起始目的地。

如果该方法返回 false,则 NavController.getCurrentDestination() 会返回 null。您应负责导航到新目的地,或通过对 Activity 调用 finish() 来处理弹出情况,如下例所示:

if (!navController.popBackStack()) {
    // Call finish() on your Activity
    finish()
}

通过 引用其他导航图

在导航图中,您可以使用 include 引用其他图。虽然这在功能上与使用嵌套图相同,但 include 可让您使用其他项目模块或库项目中的图,如以下示例所示:

<!-- (root) nav_graph.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/nav_graph"
    app:startDestination="@id/fragment">

    <include app:graph="@navigation/included_graph" />

    <fragment
        android:id="@+id/fragment"
        android:name="com.example.myapplication.BlankFragment"
        android:label="Fragment in Root Graph"
        tools:layout="@layout/fragment_blank">
        <action
            android:id="@+id/action_fragment_to_second_graph"
            app:destination="@id/second_graph" />
    </fragment>

    ...
</navigation>
<!-- included_graph.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/second_graph"
    app:startDestination="@id/includedStart">

    <fragment
        android:id="@+id/includedStart"
        android:name="com.example.myapplication.IncludedStart"
        android:label="fragment_included_start"
        tools:layout="@layout/fragment_included_start" />
</navigation>

创建全局操作

您可以使用全局操作来创建可由多个目的地共用的通用操作。例如,您可能想要不同目的地中的多个按钮导航到同一应用主屏幕。

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
            xmlns:tools="http://schemas.android.com/tools"
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:id="@+id/main_nav"
            app:startDestination="@id/mainFragment">

  ...

  <action android:id="@+id/action_global_mainFragment"
          app:destination="@id/mainFragment"/>

</navigation>

如需在代码中使用某个全局操作,请将该全局操作的资源 ID 传递到每个界面元素的 navigate() 方法,如以下示例所示:

viewTransactionButton.setOnClickListener { view ->
    view.findNavController().navigate(R.id.action_global_mainFragment)
}

使用 Bundle 传递参数

我们可以使用 Bundle 对象在目的地之间传递参数。创建 Bundle 对象并调用 navigate() 将它传递给目的地:

val bundle = bundleOf("amount" to amount)view.findNavController().navigate(R.id.confirmationAction, bundle)

在接收目的地的代码中,请使用 getArguments() 方法来检索 Bundle 并使用其内容:

val tv = view.findViewById<TextView>(R.id.textViewAmount)
tv.text = arguments?.getString("amount")

NavigationUI

导航图是Navigation组件中很重要的一部分,它可以帮助我们快速了解页面之间的关系,再通过NavController便可以完成页面的切换工作。而在页面的切换过程中,通常还伴随着App bar中menu菜单的变化。对于不同的页面,App bar中的menu菜单很可能是不一样的。App bar中的各种按钮和菜单,同样承担着页面切换的工作。例如,当ActionBar左边的返回按钮被单击时,我们需要响应该事件,返回到上一个页面。既然Navigation和App bar都需要处理页面切换事件,那么,为了方便管理,Jetpack引入了NavigationUI组件,使App bar中的按钮和菜单能够与导航图中的页面关联起来。

NavigationUI 支持以下顶部应用栏类型:

  • Toolbar
  • CollapsingToolbarLayout
  • ActionBar
override fun onCreate(savedInstanceState: Bundle?) {
    ...

    val navHostFragment =
        supportFragmentManager.findFragmentById(R.id.nav_host_fragment) as NavHostFragment
    val navController = navHostFragment.navController
    val appBarConfiguration = AppBarConfiguration(
        topLevelDestinationIds = setOf(),
        fallbackOnNavigateUpListener = ::onSupportNavigateUp
    )
    findViewById<Toolbar>(R.id.toolbar)
        .setupWithNavController(navController, appBarConfiguration)
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/192429.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java实现集合和Excel文件相互转换

目录 一、集合转化为Excel文件二、Excel文件转化为集合 一、集合转化为Excel文件 效果如下&#xff0c;是将集合转化为Excel文件&#xff0c;Excel包含合并单元格。 实体类&#xff1a; Data public class ClassGrade {/** 年级 */private String grade;/** 班主任 */privat…

智汇方象惠管家:提升电商系统与广告推广的效率,实现无代码开发的连接

无代码开发的连接优势 在当今快速发展的电商领域&#xff0c;商家们急需一个既能优化电商系统又能提升客服体验的解决方案。智汇方象的惠管家&#xff0c;一个基于云计算的SAAS服务&#xff0c;就是为了满足这一需求而生。这款工具通过无代码开发的方式&#xff0c;使得连接和…

中国北斗:守护萨雷兹湖一方安澜

中国北斗&#xff1a;守护萨雷兹湖一方安澜 在第三届“一带一路”国际合作高峰论坛数字经济高级别论坛上&#xff0c;由中国经济信息社、国家发展改革委高技术司、国家数据局联合编制的《数字“慧”就发展之路》中英文图文集正式发布&#xff0c;展现了中国与共建“一带一路”国…

Codeforces Round 911 (Div. 2) --- D题题解

D. Small GCD Problem - D - Codeforces 题目大意&#xff1a; 给你一个数组&#xff0c;你可以在里面任选三个数ai aj ak&#xff0c;要求i j k 互不相同&#xff0c; 现定义一个函数f(a,b,c)gcd(a,b)&#xff0c;其中a 和 b为a&#xff0c;b&#xff0c;c中较小的两个。求f…

Callable、Future和FutrueTask详解

一、Callable介绍 1.1 Runnable介绍 Runnable是一个接口&#xff0c;里面声明了run方法。但是由于run方法返回值类型为void&#xff0c;所以在执行完成任务后&#xff0c;无法返回任何结果。 FunctionalInterface public interface Runnable {public abstract void run(); }…

SIFT尺度不变特征变换

SIFT(Scale-Invariant Feature Transform)是一种用于图像处理和计算机视觉中的特征提取和匹配的算法。它的主要优点是对图像的尺度、旋转和亮度变化具有较强的鲁棒性。 基本原理: Scale-space peak selection: Potential location for finding features.Keypoint Localizat…

Redis 命令处理过程

我们知道 Redis 是一个基于内存的高性能键值数据库, 它支持多种数据结构, 提供了丰富的命令, 可以用来实现缓存、消息队列、分布式锁等功能。 而在享受 Redis 带来的种种好处时, 是否曾好奇过 Redis 是如何处理我们发往它的命令的呢&#xff1f; 本文将以伪代码的形式简单分析…

【活动回顾】ABeam 德硕| 艾宾信息技术开发(西安)西北高校行——与西北三所高校签订校企合作协议

前言 INTRODUCTION 10月下旬&#xff0c;ABeam旗下艾宾信息技术开发&#xff08;西安&#xff09;校招团队来到宁夏大学、青海大学、兰州大学这三所高校&#xff0c;就校企合作达成多项共识并举行了隆重的签约仪式。ABeam大中华区董事长兼总经理中野洋辅先生也特意留出时间莅临…

【活动回顾】sCrypt在2023伦敦区块链大会上的精彩表现

2023伦敦区块链大会&#xff0c;是本年度最盛大的比特币及区块链行业活动。大会于2023年5月31日至6月2日&#xff0c;在伦敦女王伊丽莎白二世中心举行&#xff0c;旨在展示BSV区块链的真正潜力。 sCrypt Inc 的创始人兼 CEO 刘晓晖&#xff0c; 作为演讲嘉宾出席了会议。他向大…

FreeImage 编译安装

FreeImage下载&#xff1a; The FreeImage Project 点击第6行&#xff1a; Download FreeImage 3.18.0 或&#xff1a; wget http://downloads.sourceforge.net/freeimage/FreeImage3170.zip #解压 unzip FreeImage3170.zip -d freeImage 编译FreeImage源代码可能需要遵循…

抓包工具安装

charles的安装 参考链接:[Python3网络爬虫开发实战] 1.7.1-Charles的安装 | 静觅 说明: 1.电脑端+手机端 都需要安装证书,安装证书是为了能抓取https协议的接口 2.手机端设置wifi的网络代理 + 电脑端设置代理端口,即可实现抓包。 特定流量抓包 HttpCanary(安装在手机里…

echarts散点图(象限图)设置不同的颜色

如图所示&#xff1a; <template><div ref"sdtcmijy" :style"{height:scrollerHeight}"></div> </template> <script> import {getXxt} from ./../requestAPI.jsexport default {data(){return {params:{},seriesData:[],…

Vue快速实践总结 · 上篇

文章目录 模板语法数据绑定事件处理计算属性监视属性&#xff08;监听器&#xff09;条件渲染列表渲染数据监视原理内置指令总结生命周期组件化编程组件使用步骤组件的嵌套this指向单文件组件ref、props 脚手架(Vue CLI)render函数 参考自己的Vue专栏以及Vue官方文档 模板语法 …

10 个例子带你学会 AI 编程(含提示词)

大家好&#xff0c;我是伍六七。 AI 编程是一个程序员群体普遍关注的领域&#xff0c;但是真的使用 AI 编程实现提效的还是少数。 有的人没有大模型资源&#xff0c;有的人不知道可以在哪些方面使用 AI 进行提效&#xff0c;还有的人不相信使用 AI 可以提效。 今天&#xff…

用java实现王者荣耀

第一步是创建项目 项目名自拟 第二部创建个包名 来规范class 然后是创建类 GameFrame 运行类 package com.sxt; import java.awt.Graphics; import java.awt.Image; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; impo…

【开源】基于Vue和SpringBoot的数字化社区网格管理系统

项目编号&#xff1a; S 042 &#xff0c;文末获取源码。 \color{red}{项目编号&#xff1a;S042&#xff0c;文末获取源码。} 项目编号&#xff1a;S042&#xff0c;文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、开发背景四、系统展示五、核心源码5…

数据结构—树

文章目录 9.树(1).树的基本概念#1.基本定义#2.树的广义表表示法#3.基本术语 (2).树的存储结构#1.标准形式(常用)#2.逆存储形式#3.孩子兄弟存储法 (3).并查集#1.我们到底想解决什么问题#2.并查集结点#2.Find(查)#3.Union(并)#4.例子 (4).树的遍历#1.前序遍历#2.后序遍历#3.遍历的…

PHPExcel 导出Excel报错:PHPExcel_IOFactory::load()

背景 近期在做 excel文件数据导出时&#xff0c;遇到如下报错&#xff1a; iconv(): Detected an illegal character in input string场景&#xff1a;计划任务后台&#xff0c;分步导出 大数据 excel文件发现在加载文件时&#xff0c;会有报错 报错信息 如下&#xff1a; {&q…

锂电池污水如何处理

锂电池是目前应用广泛的重要电池类型&#xff0c;然而其生产过程和废弃处理中产生的污水对环境造成了不可忽视的影响。本文将探讨锂电池污水的处理方法&#xff0c;以期为环境保护和可持续发展作出贡献。 首先&#xff0c;了解锂电池污水的组成是解决问题的关键。锂电池污水通…

物理层之奈氏准则和香农定理

学习的最大理由是想摆脱平庸&#xff0c;早一天就多一份人生的精彩&#xff1b;迟一天就多一天平庸的困扰。各位小伙伴&#xff0c;如果您&#xff1a; 想系统/深入学习某技术知识点… 一个人摸索学习很难坚持&#xff0c;想组团高效学习… 想写博客但无从下手&#xff0c;急需…