Jetpack - Navigation: 一个全面的安卓开发指南

在这里插入图片描述

引言

导航是任何安卓应用程序中至关重要的部分。无缝地在不同的屏幕之间移动并传递数据,对于流畅的用户体验来说至关重要。在这篇博客中,我们将深入探讨Jetpack的Navigation组件,这个强大的框架旨在简化安卓应用中的导航。我们将涵盖从设置和配置到高级使用场景的所有内容。

什么是Jetpack Navigation?

Jetpack Navigation是Android Jetpack的一部分,Jetpack是一个库套件,帮助开发者遵循最佳实践,减少样板代码,并在不同版本的安卓之间编写一致的代码。Navigation组件帮助管理导航,从简单的按钮点击到更复杂的模式,如导航抽屉和底部导航。

设置Jetpack Navigation

在深入使用之前,让我们先在你的项目中设置Navigation组件。

步骤1:添加依赖项

首先,在你的build.gradle文件中添加必要的依赖项。

dependencies {
    def nav_version = "2.7.7"

    // Java语言实现
    implementation "androidx.navigation:navigation-fragment:$nav_version"
    implementation "androidx.navigation:navigation-ui:$nav_version"

    // Kotlin
    implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
    implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
}

步骤2:创建导航图

导航图是一个XML资源,集中定义了所有与导航相关的信息。在res/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" app:startDestination="@id/homeFragment">

   <fragment android:id="@+id/homeFragment" android:name="com.example.app.HomeFragment"
       android:label="Home" tools:layout="@layout/fragment_home" />

   <fragment android:id="@+id/detailsFragment" android:name="com.example.app.DetailsFragment"
       android:label="Details" tools:layout="@layout/fragment_details">
       <argument android:name="itemId" app:argType="integer" />
   </fragment>

</navigation>

在目的地之间导航

设置好导航图后,让我们来探索如何在不同的目的地之间进行导航。

基本导航

要从HomeFragment导航到DetailsFragment,可以使用NavController。这可以通过在HomeFragment
中的一个简单按钮点击来完成。

class HomeFragment : Fragment(R.layout.fragment_home) {

   override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
       super.onViewCreated(view, savedInstanceState)

       val navController = findNavController()

       view.findViewById<Button>(R.id.navigateToDetailsButton).setOnClickListener {
           val action = HomeFragmentDirections.actionHomeFragmentToDetailsFragment(itemId = 1)
           navController.navigate(action)
       }
   }
}

传递数据

数据可以通过Safe Args在目的地之间传递。在上面的例子中,我们将itemId传递给了DetailsFragment

DetailsFragment中,按照以下方法获取参数:

class DetailsFragment : Fragment(R.layout.fragment_details) {

   override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
       super.onViewCreated(view, savedInstanceState)

       val args: DetailsFragmentArgs by navArgs()
       val itemId = args.itemId

       // 使用itemId
   }
}

处理上和返回操作

Navigation组件自动处理上和返回操作。当使用NavController时,返回操作由Navigation UI库管理。

在Activity中设置

在你的MainActivity中,你需要设置NavController并配置ActionBar。

class MainActivity : AppCompatActivity() {

   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContentView(R.layout.activity_main)

       val navController = findNavController(R.id.nav_host_fragment)
       setupActionBarWithNavController(navController)
   }

   override fun onSupportNavigateUp(): Boolean {
       val navController = findNavController(R.id.nav_host_fragment)
       return navController.navigateUp() || super.onSupportNavigateUp()
   }
}

高级导航模式

底部导航

Jetpack Navigation轻松支持底部导航。在res/menu中定义菜单项,并设置NavHostFragment以使用底部导航。


<menu xmlns:android="http://schemas.android.com/apk/res/android">
   <item android:id="@+id/homeFragment" android:icon="@drawable/ic_home" android:title="Home" />
   <item android:id="@+id/detailsFragment" android:icon="@drawable/ic_details"
       android:title="Details" />
</menu>
class MainActivity : AppCompatActivity() {

   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContentView(R.layout.activity_main)

       val navController = findNavController(R.id.nav_host_fragment)
       val bottomNavigationView = findViewById<BottomNavigationView>(R.id.bottom_nav)
       bottomNavigationView.setupWithNavController(navController)
   }
}

侧边导航抽屉

与底部导航类似,侧边导航抽屉也可以无缝集成。定义抽屉项并设置NavHostFragment


<menu xmlns:android="http://schemas.android.com/apk/res/android">
   <item android:id="@+id/homeFragment" android:icon="@drawable/ic_home" android:title="Home" />
   <item android:id="@+id/detailsFragment" android:icon="@drawable/ic_details"
       android:title="Details" />
</menu>
class MainActivity : AppCompatActivity() {

   private lateinit var drawerLayout: DrawerLayout

   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContentView(R.layout.activity_main)

       drawerLayout = findViewById(R.id.drawer_layout)
       val navController = findNavController(R.id.nav_host_fragment)
       val navView: NavigationView = findViewById(R.id.nav_view)
       navView.setupWithNavController(navController)

       setupActionBarWithNavController(navController, drawerLayout)
   }

   override fun onSupportNavigateUp(): Boolean {
       val navController = findNavController(R.id.nav_host_fragment)
       return NavigationUI.navigateUp(navController, drawerLayout) || super.onSupportNavigateUp()
   }
}

动态添加Fragment

有时候,你可能需要在运行时动态添加Fragment。Jetpack Navigation也支持这种场景。

  1. 创建一个新的Fragment,例如DynamicFragment
class DynamicFragment : Fragment(R.layout.fragment_dynamic) {

   override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
       super.onViewCreated(view, savedInstanceState)
       // Fragment逻辑
   }
}
  1. 在导航图中添加一个dynamicFragment

<fragment android:id="@+id/dynamicFragment" android:name="com.example.app.DynamicFragment"
   android:label="Dynamic" tools:layout="@layout/fragment_dynamic" />
  1. 在你的代码中动态添加Fragment。
class MainActivity : AppCompatActivity() {

   override fun onCreate(savedInstanceState: Bundle?) {
       super.onCreate(savedInstanceState)
       setContentView(R.layout.activity_main)

       val navController = findNavController(R.id.nav_host_fragment)

       val fragment = DynamicFragment()
       supportFragmentManager.beginTransaction()
           .replace(R.id.nav_host_fragment, fragment)
           .addToBackStack(null)
           .commit()
   }
}

复杂导航示例:导航图中嵌套导航图

在大型应用中,你可能会遇到需要嵌套导航图的情况。嵌套导航图可以帮助你组织和管理复杂的导航层次结构。

主导航图

在主导航图中定义一个包含子导航图的<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" app:startDestination="@id/mainFragment">

   <fragment android:id="@+id/mainFragment" android:name="com.example.app.MainFragment"
       android:label="Main" tools:layout="@layout/fragment_main" />

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

</navigation>

嵌套导航图

创建一个新的导航图文件,例如nested_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" app:startDestination="@id/nestedFragmentA">

   <fragment android:id="@+id/nestedFragmentA" android:name="com.example.app.NestedFragmentA"
       android:label="Nested A" tools:layout="@layout/fragment_nested_a" />

   <fragment android:id="@+id/nestedFragmentB" android:name="com.example.app.NestedFragmentB"
       android:label="Nested B" tools:layout="@layout/fragment_nested_b" />

</navigation>

这样,你可以在主导航图中导航到子导航图中的目的地。

class MainFragment : Fragment(R.layout.fragment_main) {

   override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
       super.onViewCreated(view, savedInstanceState)

       val navController = findNavController()

       view.findViewById<Button>(R.id.navigateToNestedButton).setOnClickListener {
           navController.navigate(R.id.nestedFragmentA)
       }
   }
}

结论

Jetpack Navigation简化了安卓导航中的复杂性,提供了一个强大的框架来管理各种导航场景。从基本的Fragment事务到更复杂的导航模式如底部导航和侧边导航抽屉,Navigation组件提高了开发过程的可管理性和效率。

Best regards!

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

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

相关文章

应急响应靶机-Linux(1)

前言 本次应急响应靶机采用的是知攻善防实验室的Linux-1应急响应靶机 靶机下载地址为&#xff1a; https://pan.quark.cn/s/4b6dffd0c51a 相关账户密码&#xff1a; defend/defend root/defend 解题 第一题-攻击者的IP地址 先找到的三个flag&#xff0c;最后才找的ip地址 所…

openinstall拥抱鸿蒙生态,SDK全面适配HarmonyOS NEXT

作为国内领先的App渠道统计与深度链接服务商&#xff0c;openinstall持续推动鸿蒙生态建设&#xff0c;近日正式发布openinstall HarmonyOS SDK&#xff0c;并成功入驻鸿蒙生态伙伴SDK专区&#xff0c;成为华为鸿蒙生态的合作伙伴&#xff0c;为鸿蒙应用开发者带来安全合规、高…

C语言的内存知识

这节我们主要认识一下内存&#xff0c;便于理解指针操作和后续内存管理。 一、内存分区模型 C程序在执行时&#xff0c;将内存大方向划分为4个区域 &#xff08;可以结合函数小节的函数栈帧部分看一下&#xff09; ⚪ 代码区:存放函数体的二进制代码&#xff0c;由操作系统进…

Java | Leetcode Java题解之第174题地下城游戏

题目&#xff1a; 题解&#xff1a; class Solution {public int calculateMinimumHP(int[][] dungeon) {int n dungeon.length, m dungeon[0].length;int[][] dp new int[n 1][m 1];for (int i 0; i < n; i) {Arrays.fill(dp[i], Integer.MAX_VALUE);}dp[n][m - 1] …

HarmonyOS ArkUi Tabs+TabContent+List实现tab吸顶功能

Demo效果 Entry Component struct StickyNestedScroll {State message: string Hello WorldState arr: number[] []scroller new Scroller()StyleslistCard() {.backgroundColor(Color.White).height(72).width("100%").borderRadius(12)}build() {Scroll(this.sc…

火山引擎ByteHouse:新一代云数仓必不可少的五大核心能力

从数据库领域的发展历程来看&#xff0c;分析型数据库已有 40 多年的发展历史&#xff0c;与数据库基本同时代。从OLTP 和 OLAP 的分支来看&#xff0c;分析型数据库支持了海量数据规模下的聚合性分析。尤其是随着移动互联网甚至 AI 等领域的发展&#xff0c;用户画像行为分析的…

AFLNet入门教学——测试RTSP协议实现Live555(Ubuntu)

1、简介 本文旨在使用AFLNet对RTSP协议实现Live555进行模糊测试。实验环境为&#xff1a;Ubuntu22.04.4AFLNet安装参考&#xff1a;AFLNet入门教学——安装&#xff08;Ubuntu22.04.4&#xff09;-CSDN博客 2、安装Live555 本次实验采取的是live555在2018年8月28日上传的版本…

【应届应知应会】Linux常用指令

SueWakeup 个人主页&#xff1a;SueWakeup 系列专栏&#xff1a;学习技术栈 个性签名&#xff1a;保留赤子之心也许是种幸运吧 本文封面由 凯楠&#x1f4f8;友情提供 目录 文件与目录管理 目录操作命令&#xff1a; ls [选项] [目录或文件] mkdir 文件操作命令&#xf…

Django 如何使用视图动态输出 CSV 以及 PDF

Django 如何使用视图动态输出 CSV 以及 PDF 这一篇我们需要用到 python 的 csv 和 reportLab 库&#xff0c;通过django视图来定义输出我们需要的 csv 或者 pdf 文件。 csv文件 打开我们的视图文件 testsite/members/views.py 。新增一个视图方法&#xff1a; import csv …

链在一起怎么联机 链在一起远程同玩联机教程

steam中最近特别热门的多人跑酷冒险的游戏&#xff1a;《链在一起》&#xff0c;英文名称叫做Chained Together&#xff0c;在游戏中我们需要开始自己的旅程&#xff0c;在地狱的深处&#xff0c;与我们的同伴被链在一起。我们的任务是通过尽可能高的攀登逃离地狱。每一次跳跃都…

【Python机器学习】自动化特征选择——迭代特征选择

在单变量测试中&#xff0c;没有使用模型&#xff1b;在基于模型的选择中&#xff0c;使用单个模型来选择特征。而在迭代特征选择中&#xff0c;将会构造一系列模型&#xff0c;每个模型都使用不同数量的特征。有两种基本方法&#xff1a; 1、开始时没有特征&#xff0c;然后逐…

前端主流框架-JQuery

Javascript DOM 1 DOM模型Document对象 1.1 DOM模型 DOM【Document Object Model】 &#xff1a;文档对象模型。直白的讲就是通过程序解析结构化文档&#xff08;xml&#xff0c;html&#xff09;的时候&#xff0c;在内存中生成的包含当前结构化文档中所有内容的一个对象模型…

openlayers 轨迹回放(历史轨迹)(postrender事件和render方法)

openlayers 轨迹回放&#xff08;历史轨迹&#xff09;&#xff08;postrender事件和render方法&#xff09; 本篇介绍一下使用openlayers轨迹回放&#xff08;历史轨迹&#xff09;&#xff08;postrender事件和render方法&#xff09; 1 需求 轨迹回放&#xff08;历史轨迹…

网络问题排障专题-AF网络问题排障

目录 一、数据交换基本原理 1、ARP协议工作原理 数据包如图&#xff1a; 2、二层交换工作原理 简述核心概念&#xff1a; 二层交换原理-VLAN标签 3、三层交换工作原理 二、AF各种部署模式数据转发流程 1、路由模式数据转发流程 三、分层/分组逐一案例讲解 1、问题现…

《非暴力沟通》

The English name of the book: Nonviolent Communication 我对《非暴力沟通》的理解总归于一句话&#xff1a;我们所认识的世界&#xff0c;来源于我们的认知里的世界。我们总喜欢用“说教”的方式&#xff0c;评论他人的行为。这本书讲述如何摘掉偏见。 文章&#xff1a;

海外仓货物何如高效入库:入库区域规划策略,附规划图

作为海外仓布局的一部分&#xff0c;入库区可以说是所有业务流程的开端&#xff0c;也是最重要的区域之一。如果海外仓的入库区布局不合理&#xff0c;会直接导致后续所有的作业流程都出现拥堵、低效。 今天我们就会给大家分享海外仓入库区的规划指南&#xff0c;通过科学的规…

压缩pdf文件大小的方法,如何压缩pdf格式的大小

pdf太大怎么压缩&#xff1f;当你需要通过电子邮件发送一个PDF文件&#xff0c;却发现文件太大无法成功发出时&#xff0c;这些情况下&#xff0c;我们都需要找到一种方法来压缩PDF文件&#xff0c;以便更便捷地进行分享和传输。PDF文件的大小通常与其中包含的图片、图形和文本…

leetCode.91. 解码方法

leetCode.91. 解码方法 题目思路 题解 class Solution { public:int numDecodings(string s) {int n s.size();// dp 中f[0]一般不做使用&#xff0c;只是存一个初值1&#xff0c;表示默认由一种方案s s;vector<int> f( n 1 );f[0] 1;for ( int i 1; i < n;…

SRC公益上分的小技巧二

前言 漏洞挖掘有时候换几个思路&#xff0c;事半功倍 下面讲解一些很简单&#xff0c;但是实用的思路 案例一、若依系统配置不当 讲解了这么多系统&#xff0c;兜兜转转又回到了若依 其实最早的若依系统&#xff0c;在js中已经将账号密码自动填充&#xff0c;我们一访问就…

1、加密算法-MD5随机盐

一、说明 MD5消息摘要算法&#xff0c;属Hash算法一类。MD5算法对输入任意长度的消息进行运行&#xff0c;产生一个128位的消息摘要(32位的数字字母混合码)。 二、主要特点 不可逆&#xff0c;相同数据的MD5值肯定一样&#xff0c;不同数据的MD5值不一样 (一个MD5理论上的确…