Jetpack系列:应用内导航的正确使用方法

逻辑棱镜
• 阅读 4393

今天小编要分享的还是Android Jetpack库的基本使用方法,本篇介绍的内容是Jetpack Navigation组件,让我们一起学习,为完成年初制定的计划而努力吧!


组件介绍



导航,是指提供用户在应用程序中的不同内容之间进行浏览、退出的交互功能。如我们在Android手机上常常用到的物理/虚拟返回按键、桌面(Home)键、历史记录(Recent)键、ActionBar 返回键等等。

Jetpack库中的Navigation组件由以下三个关键部分组成:
  • 导航图:一种XML资源,包含所有与导航有关的信息,如Fragment配置、跳转行为/方向、动画等等;
  • NavHost:一个空容器,用于显示导航图中的目的地,项目中需要包含一个实现NavHost接口的默认NavHostFragment容器;
  • NavController:在NavHost容器内管理应用程序的导航行为。当用户在应用程序中切换界面时,NavController协调容器中的目标内容交换。

优点

使用导航组件有很多好处:
  • 能够处理Fragment切换
  • 能够正确处理向上、返回的默认行为
  • 提供动画和过渡的标准化资源
  • 提供深层链接功能
  • 包含导航UI模式,例如抽屉导航和底部导航,开发者无需进行额外的处理
  • 保护导航之间数据传递的类型安全
  • 提供ViewModel支持,多Fragment间可共享ViewModel数据
  • 提供AndroidStudio图形化查看/编辑导航功能(>= 3.3版本)

简单使用



下面是一个使用导航组件进行开发的Demo运行效果:

Jetpack系列:应用内导航的正确使用方法

从实现效果上来看,整个应用程序共有8个界面,分别是主界面、注册界面、排行界面、用户匹配、游戏界面、失败界面、成功界面、用户界面。

主要涉及的逻辑有:
  • 打开应用进入主界面
  • 主界面提供两个功能,一个开始注册;另一个进入排行界面
  • 注册界面提供开始匹配功能
  • 用户匹配提供开始游戏功能
  • 游戏界面操作后会进入成功或失败界面
  • 游戏成功界面可进入排行界面或匹配界面继续游戏
  • 游戏失败界面可返回到匹配界面重试
  • 排行界面可进入用户界面查看信息

好了,整个应用界面之间涉及的主要逻辑都已经理清楚了,开始导入Jetpack导航组件。

环境配置

  • 使用AS 3.3及以上版本
  • 添加依赖项支持
implementation deps.navigation.fragment_ktx
implementation deps.navigation.runtime_ktx
//implementation "androidx.navigation:navigation-fragment-ktx:2.1.0"
//implementation "androidx.navigation:navigation-ui-ktx:2.1.0"

导航图

导航图的创建是整个应用的核心所在,它描述了所有行为的触发顺序。通过AS Design功能可看到整个应用的界面并且覆盖所有界面可能执行的顺序。

Jetpack系列:应用内导航的正确使用方法



使用AndroidStudio创建导航图时,选择Resource type为navigation,默认会创建res/navigation目录,并将资源文件放置于此目录下。

以title_screen主界面配置为例,来看一下xml的构成:

<navigation ...
            //指定了启动当前导航时显示的界面
            app:startDestination="@+id/title_screen">
  <fragment
      android:id="@+id/title_screen"
      android:name="com.example.android.navigationsample.TitleScreen"
      android:label="fragment_title_screen"
      tools:layout="@layout/fragment_title_screen">
      //每一个action都代表了界面上提供跳转到其他界面的行为
      <action
              android:id="@+id/action_title_screen_to_register"
              app:destination="@id/register"
              app:popEnterAnim="@anim/slide_in_left"
              app:popExitAnim="@anim/slide_out_right"
              app:enterAnim="@anim/slide_in_right"
              app:exitAnim="@anim/slide_out_left"/>
      //设置了动画和过渡效果
      <action
              android:id="@+id/action_title_screen_to_leaderboard"
              app:destination="@id/leaderboard"
              app:popEnterAnim="@anim/slide_in_left"
              app:popExitAnim="@anim/slide_out_right"
              app:enterAnim="@anim/slide_in_right"
              app:exitAnim="@anim/slide_out_left"/>
  </fragment>
.../>       

在导航图配置时,有四个需要注意的属性:

  • popUpTo
  • popUpToInclusive
  • launchSingleTop
  • deepLink
//launchSingleTop代表启动当前fragment后,会栈顶复用
<action
      android:id="@+id/action_register_to_match"
      app:destination="@id/match"
      app:enterAnim="@anim/slide_in_right"
      app:exitAnim="@anim/slide_out_left"
      app:launchSingleTop="true"
      app:popEnterAnim="@anim/slide_in_left"
      app:popExitAnim="@anim/slide_out_right" />

//deepLink及深度链接,应用可通过Uri方式启动当前Fragment:
//holder.item.findNavController().navigate(Uri.parse("https://www.example.com/user/Flo"))
//此种方法为静态配置,动态配置方法请参考官方说明文档
<fragment
        android:id="@+id/user_profile"
        android:name="com.example.android.navigationsample.UserProfile"
        android:label="fragment_user_profile"
        tools:layout="@layout/fragment_user_profile">
    <argument android:name="userName"
              android:defaultValue="name"/>
    <deepLink app:uri="www.example.com/user/{userName}" />
</fragment>
<action
    android:id="@+id/action_in_game_to_resultsWinner"
    app:destination="@id/results_winner"
    app:popUpTo="@+id/match"
    app:popUpToInclusive="false"
    app:popEnterAnim="@anim/slide_in_left"
    app:popExitAnim="@anim/slide_out_right"
    app:enterAnim="@anim/fade_in"
    app:exitAnim="@anim/fade_out"/>
//popUpTo属性表示堆栈返回到某个界面,其后的栈数据清空
//popUpToInclusive属性为true表示回到指定界面时,界面栈中是否还包括当前界面
//(如果栈中已经包含了指定要跳转的界面,那么只会保留一个,不指定则栈中会出现两个
//界面相同的Fragment数据)

AndroidManifest与布局文件配置

如果要使用导航组件的深度链接功能,则需要在AndroidManifest中声明导航图,以便深度链接功能正常使用。

<activity...
<nav-graph android:value="@navigation/navigation" />
...
</activity>

导航功能的使用需要在NavHostFragment容器中实现,因此需要指定布局显示时使用的容器,设置默认NavHost,设置导航图。

<layout>...
<fragment
    android:id="@+id/my_nav_host_fragment"
    android:name="androidx.navigation.fragment.NavHostFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:defaultNavHost="true"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:navGraph="@navigation/navigation"/>
.../>

代码实现

整个Demo使用单Activity,多Fragment架构,MainActivity启动时,加载NavHostFragment容器,解析navigation容器图,通过startDestination属性找到首界面进行显示(本例首界面为TitleScreen)。

如下为TitleScreen的代码实现:

class TitleScreen : Fragment() {
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
    ): View? {
        val view = inflater.inflate(R.layout.fragment_title_screen, container, false)

        view.findViewById<Button>(R.id.play_btn).setOnClickListener {
            Navigation.findNavController(view).navigate(R.id.action_title_screen_to_register)
        }...
        return view
    }
}

到此,使用导航组件进行应用程序开发的基本流程已经结束,当然导航组件提供的功能远不止如此,它还有如页面间数据类型的安全保护,手势导航,导航嵌套、条件导航,自定义动画过渡效果,使用NavigationUI更新界面等高级使用方法。具体使用可参考Google官方文档说明。

源码在此

- END -


更多科技资讯,新技术学习

Jetpack系列:应用内导航的正确使用方法

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Wesley13 Wesley13
4年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Easter79 Easter79
4年前
Taro小程序自定义顶部导航栏
微信自带的顶部导航栏是无法支持自定义icon和增加元素的,在开发小程序的时候自带的根本满足不了需求,分享一个封装好的组件,支持自定义icon、扩展dom,适配安卓、ios、h5,全面屏。我用的是京东的Taro多端编译框架写的小程序,原生的也可以适用,用到的微信/taro的api做调整就行,实现效果如下。!在这里插入图片描述(https://i
Easter79 Easter79
4年前
SwiftUI直通车系列(3)—— 使用导航
SwiftUI直通车系列三(3)——使用导航  关于SwiftUI,我们前两篇博客介绍了独立组件的布局与属性设置相关内容,并且介绍了开发中最常用的列表视图的使用。但是一个完整的应用程序不可能是单界面的,如何使用SwiftUI进行界面间的导航跳转,是我们本博客讨论的重点。前两篇博客地址如下:Swi
Wesley13 Wesley13
4年前
FLV文件格式
1.        FLV文件对齐方式FLV文件以大端对齐方式存放多字节整型。如存放数字无符号16位的数字300(0x012C),那么在FLV文件中存放的顺序是:|0x01|0x2C|。如果是无符号32位数字300(0x0000012C),那么在FLV文件中的存放顺序是:|0x00|0x00|0x00|0x01|0x2C。2.  
Wesley13 Wesley13
4年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Stella981 Stella981
4年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
布局王 布局王
7个月前
鸿蒙仓颉开发语言实战教程:实现商城应用首页
经过了几天的入门教程,我们终于进入到了仓颉开发语言的实战环节,今天分享的内容是实现商城应用的首页页面,效果图如下:首页的内容包括导航栏、轮播图、商品分类和商品列表,我们下面逐一介绍。导航栏仓颉语言中是没有导航栏组件的,我们需要自己去开发。此处的导航栏也比较
布局王 布局王
7个月前
鸿蒙Next仓颉语言开发实战教程:设置页面
仓颉语言商城应用的页面开发教程接近尾声了,今天要分享的是设置页面:导航栏还是老样式,介绍过很多次了,今天不再赘述。这个页面的内容主要还是介绍List容器的使用。可以看出列表内容分为三组,所以我们要用到ListItemGroup,不过第一组是没有标题的,所以