Jetpack Navigation页面导航

Jetpack Navigation页面导航

简介
该组件可以实现用户界面跳转、转场动画以及安全的参数传递等功能。无论是简单的按钮点击,还是应用栏和抽屉式导航栏等更为复杂的模式,该组件均可应对。还可以使用 Android Studio 的 Navigation Editor 来查看和编辑导航图,使页面跳转流程更加直观。
Navigation 组件旨在用于具有一个主 Activity 和多个 Fragment 目的地的应用

依赖
在app的build.gradle文件中添加依赖:

dependencies {
    ......

    def nav_version = "2.3.0"

    // Navigation依赖(Java版)
    //implementation "androidx.navigation:navigation-fragment:$nav_version"
    //implementation "androidx.navigation:navigation-ui:$nav_version"

    // Navigation依赖(Kotlin版)
    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"

    // 测试模块
    //androidTestImplementation "androidx.navigation:navigation-testing:$nav_version"
}

如果要使用Safe Args的话,还需要添加插件依赖,
在项目的build.gradle文件中添加依赖:

dependencies {
    ......
    
    def nav_version = "2.3.0-alpha01"
    classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
}

在app的build.gradle文件最上面添加依赖:

//适用于 Kotlin 独有的模块的 Kotlin 代码
apply plugin: "androidx.navigation.safeargs.kotlin"
//或
//适用于 Java 或 Java 和 Kotlin 混合模块的 Java 语言代码
//apply plugin: "androidx.navigation.safeargs"

使用步骤
1、创建导航图
2、添加导航宿主NavHost
3、添加目的地
4、连接目的地

创建导航图
右键点击res目录–>选择New–>选择Android Resource File
Jetpack Navigation页面导航_第1张图片

创建一个导航图文件app_graph.xml
Jetpack Navigation页面导航_第2张图片

在资源目录下,生成一个navigation导航文件夹和一个app_graph.xml导航图文件
Jetpack Navigation页面导航_第3张图片

添加导航宿主NavHost
打开主Activity布局文件
Jetpack Navigation页面导航_第4张图片

添加fragment,通过设置属性,将主布局与导航图关联

<androidx.constraintlayout.widget.ConstraintLayout 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">

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

androidx.constraintlayout.widget.ConstraintLayout>
android:name  固定值(也可以自己实现NavHostFragment),NavHost 实现的类名称
app:navGraph 设置导航图文件,将 NavHostFragment 与导航图相关联
app:defaultNavHost="true" 拦截系统返回按钮,多级Fragment界面,逐级返回

添加目的地
如果没有提前创建fragment界面,需要创建一个新的frament(目的地),
如果创建过,则可以直接选择已经创建的fragment界面
Jetpack Navigation页面导航_第5张图片

创建一个新的fragment界面
Jetpack Navigation页面导航_第6张图片
Jetpack Navigation页面导航_第7张图片

连接目的地
鼠标按住连接点,拖动到目的地就可以连接目的地
Jetpack Navigation页面导航_第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/nva_graph"
    app:startDestination="@id/blankFragment"
    tools:ignore="UnusedNavigation">

    <fragment
        android:id="@+id/blankFragment"
        android:name="com.zzs.jetpack_navigation.BlankFragment"
        android:label="fragment_blank"
        tools:layout="@layout/fragment_blank" >
        //action相当于连接线
        <action
            android:id="@+id/action_blankFragment_to_blankFragment2"
            app:destination="@id/blankFragment2" />
    fragment>
    <fragment
        android:id="@+id/blankFragment2"
        android:name="com.zzs.jetpack_navigation.BlankFragment2"
        android:label="fragment_blank_fragment2"
        tools:layout="@layout/fragment_blank2" >
    fragment>
navigation>

界面跳转
界面跳转有有多种方式,下面介绍两种:
1、action跳转(本质上也是id跳转),需实现Safe Args插件依赖

tv_jump.setOnClickListener {
    val action = BlankFragmentDirections.actionBlankFragmentToBlankFragment2()
    it.findNavController().navigate(action)
}

actionBlankFragmentToBlankFragment2实际上就是连接目的地后生成的action中的id的驼峰式命名
actionBlankFragmentToBlankFragment2()方法的源码:

class BlankFragmentDirections private constructor() {
  companion object {
    fun actionBlankFragmentToBlankFragment2(): NavDirections =
        ActionOnlyNavDirections(R.id.action_blankFragment_to_blankFragment2)
  }
}

2、id跳转
action_blankFragment_to_blankFragment2就是连接目的地后生成的action中的id

tv_jump.setOnClickListener {
    it.findNavController().navigate(R.id.action_blankFragment_to_blankFragment2)
}

界面返回
按下返回键可直接返回上一级界面,不需要处理
如果需要主动返回上一级界面,可通过如下方式:

tv_back.setOnClickListener {
    it.findNavController().navigateUp()
    //或者
    //it.findNavController().popBackStack()
}

navigateUp和popBackStack都可以返回上一级
区别:
navigateUp 如果当前的返回栈是空会停留在当前页面
popBackStack 如果当前的返回栈是空会报错

转场动画
设置转场动画有两种方式:
1、手动代码设置
在导航图文件中,添加如下代码:

<fragment
    android:id="@+id/blankFragment"
    android:name="com.zzs.jetpack_navigation.BlankFragment"
    android:label="fragment_blank"
    tools:layout="@layout/fragment_blank" >
    <action
        android:id="@+id/action_blankFragment_to_blankFragment2"
        app:destination="@id/blankFragment2"
        app:enterAnim="@anim/anim_in_enter"
        app:exitAnim="@anim/anim_in_exit"
        app:popEnterAnim="@anim/anim_out_enter"
        app:popExitAnim="@anim/anim_out_exit" />
fragment>

enterAnim 和 exitAnim 是往栈里添加一个 目的地 时两个 目的地 的动画
popEnterAnim 和 popExitAnim 是从栈里移除一个 目的地 时的动画

2、Degisn设计页属性设置
Jetpack Navigation页面导航_第9张图片

转场动画文件
在资源文件中,新建anim文件夹,添加如下文件:
anim_in_enter.xml


<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="200"
        android:fromXDelta="100%p"
        android:toXDelta="0%p" />
set>

anim_in_exit.xml


<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="200"
        android:fromXDelta="0%p"
        android:toXDelta="-100%p" />
set>

anim_out_enter.xml


<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="200"
        android:fromXDelta="-100%p"
        android:toXDelta="0%p" />
set>

anim_out_exit.xml


<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:duration="200"
        android:fromXDelta="0%p"
        android:toXDelta="100%p" />
set>

传递参数
传递参数有两种方式:
1、Safe Args传值,需实现Safe Args插件依赖
在导航图文件中设置传递的参数,两种方式
①手动添加代码

<fragment
    android:id="@+id/blankFragment"
    android:name="com.zzs.jetpack_navigation.BlankFragment"
    android:label="fragment_blank"
    tools:layout="@layout/fragment_blank" >
    <action
        android:id="@+id/action_blankFragment_to_blankFragment2"
        app:destination="@id/blankFragment2"/>
    <argument
        android:name="name"
        app:argType="string"
        android:defaultValue="张三" />
    <argument
        android:name="sex"
        app:argType="string"
        android:defaultValue="" />
    <argument
        android:name="age"
        app:argType="integer"
        android:defaultValue="20" />
fragment>
②在Design设计图中通过属性添加

Jetpack Navigation页面导航_第10张图片

添加完了之后,需要重新编译项目,通过插件生成对应的文件
Jetpack Navigation页面导航_第11张图片
Jetpack Navigation页面导航_第12张图片

在目的地BlankFragment2中接收参数

 val args: BlankFragmentArgs by navArgs()

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

    private fun getArgs() {
        val name = args.name
        val sex = args.sex
        val age = args.age
        tv_agrs.text =
            "${resources.getString(R.string.send_args)}\nname=${name}\nsex=$sex\nage=$age"
    }

如果navArgs()报红,需要在在app的build.gradle文件中添加如下代码:

android {
    ......
    
    compileOptions {
        sourceCompatibility = 1.8
        targetCompatibility = 1.8
    }

    kotlinOptions {
        jvmTarget = "1.8"
    }

}
注意:我用Safe Args传值,接收到的中文参数都显示为乱码,目前没有找到解决办法

2、Bundle传值
在传值目的地BlankFragment中,代码如下:

tv_jump.setOnClickListener {
    val bundle = bundleOf(
        "name" to "张三",
        "sex" to "男",
        "age" to 20
    )
    it.findNavController().navigate(R.id.action_blankFragment_to_blankFragment2, bundle)
}

在接收目的地BlankFragment2中,代码如下:

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

    private fun getArgs() {
        val name = arguments?.getString("name")
        val sex = arguments?.getString("sex")
        val age = arguments?.getInt("age")
        tv_agrs.text =
            "${resources.getString(R.string.send_args)}\nname=${name}\nsex=$sex\nage=$age"
    }

Jetpack Navigation页面导航_第13张图片

项目地址:https://github.com/zhangzs1994/Jetpack_Navigation

你可能感兴趣的:(Jetpack,Navigation)