Navigation导航

概述

Android Jetpack 组件之一,用来实现不同片段(Fragment)之间的交互导航。且遵循谷歌官方导航既定原则

用途

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

在具有多个 Activity 目的地的应用中,每个 Activity 均拥有其自己的导航图。

优势

基础用法

  1. 资源文件中新建res/navigation/navigation.xml

  2. activity布局中需要有个一fragment与之(navigation.xml)绑定;

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    ...
    //绑定即:后续所有的导航、跳转 都是在这个main_fragment中完成了
    //所以要加`app:defaultNavHost="true"`,拦截系统的返回键,fragment内部响应
    <fragment
    android:id="@+id/main_fragment"
    android:name="androidx.navigation.fragment.NavHostFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:defaultNavHost="true"
    app:navGraph="@navigation/navigation" />
    ...
  • android:name 属性包含 NavHost 实现的类名称。
  • app:navGraph 属性将 NavHostFragment 与导航图相关联。导航图会在此 NavHostFragment 中指定用户可以导航到的所有目的地。(即navigation.xml
  • app:defaultNavHost="true" 属性确保您的 NavHostFragment 会拦截系统返回按钮。请注意,只能有一个默认 NavHost。如果同一布局(例如,双窗格布局)中有多个主机,请务必仅指定一个默认 NavHost
  1. 新建目标fragment(一个或多个),并在navigation.xml中导入,并建立导航(跳转)关系。

    Graph Editor示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    <?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/HomeFragment">
    <fragment
    //下一步中方法一对应的fragmentID
    android:id="@+id/HomeFragment"
    android:name="com.cy.navigationtest.HomeFragment"
    android:label="fragment_home"
    tools:layout="@layout/fragment_home" >
    //下一步中方法二对应的action的ID
    <action
    android:id="@+id/next_action"
    app:destination="@id/detailFragment" />
    </fragment>
    <fragment
    android:id="@+id/detailFragment"
    android:name="com.cy.navigationtest.DetailFragment"
    android:label="fragment_detail"
    tools:layout="@layout/fragment_detail" />
    </navigation>
  1. 在**主fragment**中,在对应场景下进行跳转。有两种跳转方式,代码如下:
  • 方式一:直接跳转到对应fragment,跳转规则可不受navigation.xml指使,只要xml中有这个fragment的ID就行。

    1
    2
    findNavController().navigate(R.id.HomeFragment, null)
    //fragment_one:要跳转的fragment在navigation.xml中指定的ID ; null为bundle,可不传。
  • 方式二:按navigation.xml的规则进行跳转。

    1
    2
    Navigation.createNavigateOnClickListener(R.id.next_action, null)
    //next_action为navigation.xml中指定action的ID; 跳转规则就在这个action中
  • 方式三:使用 Safe Args Gradle 插件

    我也还没搞清楚,具体看官网。

    一款Gradel平台的插件,帮助你生成相关代码。所以要在根项目的gradle中配置如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    buildscript {
    repositories {
    google()
    }
    dependencies {
    def nav_version = "2.3.1"
    classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
    }
    }

    然后在app项目的中配置:(二选一)

    1
    2
    apply plugin: "androidx.navigation.safeargs" //java
    apply plugin: "androidx.navigation.safeargs.kotlin" //kotlin

    然后,在navigation.xml中目的fragment中加入

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    <?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/HomeFragment">
    <fragment
    //下一步中方法一对应的fragmentID
    android:id="@+id/HomeFragment"
    android:name="com.cy.navigationtest.HomeFragment"
    android:label="fragment_home"
    tools:layout="@layout/fragment_home" >
    //下一步中方法二对应的action的ID
    <action
    android:id="@+id/next_action"
    app:destination="@id/detailFragment" />
    </fragment>
    <fragment
    android:id="@+id/detailFragment"
    android:name="com.cy.navigationtest.DetailFragment"
    android:label="fragment_detail"
    tools:layout="@layout/fragment_detail" />
    <argument
    android:name="girl"
    app:argType="com.cy.beautygankio.data.Girl" />//记得 Parcelable or Serializable
    </navigation>

    然后编译,gradle会自动为你生成为2个类。

    • XXXDirections: 此处XXX为起点fragment类名,如:HomeFragmentDirections。

      ​ - 该类中有一个方法,方法名是你action的名字,如:nextAction()。

    • XXXArgs: 此处的XXX为终点(目的)fragment的类名,如DetailFragmentArgs。

    跳转的方法如下:

    1
    2
    3
    4
    5
    val direction =
    XXXXDirections.action方法名(
    argument
    )
    view.findNavController().navigate(direction)

    接收方法为:

    1
    2
    3
    4
    val args: XXXArgs by navArgs()
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    val argument = args.girl
    }

    这种跳转方式官方的说法是可以确保类型安全

前两种方法就只能用bundle传参了。

1
arguments?.getSerializable("key")