JetPack架构---Navigation的使用

一、概念

JetPack中的Navigation组件,用于帮助用户实现导航。Navigation组件的主要应用场景是单activity配合多个fragment的场景,简化了过去fragment管理、导航复杂问题,提供了一套统一的标准。

1-0:Navigation的用处

Navigation的使用,有以下好处-取自官网:

  • 管理与处理 Fragment 事务。
  • 为页面跳转动画提供标准化资源。
  • 实现和处理深层链接-DeepLink。
  • 简化导航界面模式接入成本(ToolBar等),开发者只需完成极少的额外工作。
  • Safe Args - 可在目标之间导航和传递数据时提供类型安全的 Gradle 插件。

Navigation需要在Android Studio3.3或更高版本才可使用。

1-1:Navigation的元素

Navigation包含三大关键元素:

(1)导航图(xml格式的导航文件);

(2)NavHost:显示导航图中目标的空白容器;

(3)NavController:控制导航转向的控制器;

Navigation的做法,简单的说,就是把导航图,放在NavHost中,然后使用NavController控制导航的跳转。

二、示例

2-0:添加依赖

def nav_version = "2.3.0-alpha01"

// Java language implementation
implementation "androidx.navigation:navigation-fragment:$nav_version"
implementation "androidx.navigation:navigation-ui:$nav_version"

2-1:在工程的res目录下,新建导航图

res--右键点击-->选择New --> 选择Android Resource File -->在界面中Resource type中选择Navigation,Directory name默认navigation即可,之后填写File name,如nav_graph。-->确认后,在res目录下将新建一个nav_graph.xml文件,也就是导航图。

此时,我们所建立的导航图还是空白的,需要往里添加需要的Fragment。因此新建三个Fragment,分别为AFragment、BFragment、CFragment。

新建导航文件方式:

以上操作后,按界面提示继续操作即可。操作完成后,再看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"
    <!--此处指定AFragment作为起始界面-->
    app:startDestination="@id/AFragment">

    <fragment
        <!--每一个Fragment有一个唯一的Id-->
        android:id="@+id/AFragment"
        android:name="com.test.jetpackdemo.AFragment"
        android:label="fragment_a"
        tools:layout="@layout/fragment_a">
        <action
            <!--此处定义了AFragment到CFragment的动作,可以在导航图中通过拖动来实现-->
            android:id="@+id/action_AFragment_to_CFragment"
            app:destination="@id/CFragment" />
    </fragment>
    <fragment
        android:id="@+id/CFragment"
        android:name="com.test.jetpackdemo.CFragment"
        android:label="fragment_c"
        tools:layout="@layout/fragment_c">
    </fragment>
    <fragment
        android:id="@+id/BFragment"
        android:name="com.test.jetpackdemo.BFragment"
        android:label="fragment_b"
        tools:layout="@layout/fragment_b" />
</navigation>

2-2:新建NavHost

在activity的布局文件中,新建NavHost这个空白容器,默认方式如下:

<fragment
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"

        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph" />

1、android:name="androidx.navigation.fragment.NavHostFragment",系统提供的NavHostFragment作为容器。

2、app:defaultNavHost="true",表示使用系统提供的默认容器NavHostFragment
3、app:navGraph="@navigation/nav_graph",表示使用的导航图路径

2-3:NavController控制的使用

在AFragment中调用 Navigation.findNavController(nav1).navigate(R.id.CFragment);即可实现从AFragment跳转到CFragment。

一、findNavController有以下三种方式,上方使用的是第3种。

1、NavHostFragment.findNavController(Fragment fragment)  

2、Navigation.findNavController(Activity activity, @IdRes int viewId) 

3、Navigation.findNavController(View view) 

二、navigate(@IdRes int resId) 入参中的resId,可以是目标Fragment的Id,也可以是到目标Fragment的ActionId。

示例到此结束,通过以上的步骤,我们在Activity中管理Fragment的步骤,比未使用Navigation之前,已经有了明显的简化。在代码中不需要commit或者replace添加Fragment,所有的管理操作都隐性的委托给了Navigation。这也是前面提到的第一点好处:处理 Fragment 事务。

三、Navigation的其余特性说明

3-0:为页面跳转动画提供标准化资源

当你为Fragment页面之间的跳转,设置了action后,你可以针对这个action,对Enter、Exit操作加上动画效果。

3-1:实现和处理深层链接-DeepLink

在nav_graph.xml中,你可以对任意的Fragment页面,添加深层链接。所谓深层链接(DeepLink)有两种情况:

1、其他app或者H5,通过特定的隐式Intent方式,打开另一个app的内页;

2、同一个app通过显示的intent方式(如通知栏),打开该app的内页;

DeepLink在场景上应用广泛,如在微信中,点击链接,打开手机上的指定app的内页。可以用于引流、营销等。

Navigation为DeepLink提供了更简便的实现,通过两步即可实现:

1、在Fragment中添加了深层链接。

<fragment
        android:id="@+id/CFragment"
        android:name="com.test.jetpackdemo.CFragment"
        android:label="fragment_c"
        tools:layout="@layout/fragment_c">
        <!--给CFragment添加deeplink,添加完成后,在外部web等页面输入https://www.baidu1.com/...后将导航到该页面 -->
        <deepLink
            android:id="@+id/deepLink2"
            app:uri="https://www.baidu1.com/{params}" />
    </fragment>

2、在app的AndroidManifest中添加nav-graph标签,指定导航图位置

<activity android:name=".NavActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <!-- 为Activity设置<nav-graph/>标签,deeplink起效需要 -->
            <nav-graph android:value="@navigation/nav_graph" />
        </activity>

deeplink有一点需要注意,在设置uri时,请带上params。否则,外部跳转到该app时,只会跳转到主页面,而不会到指定的子页面。

3-2:导航栏(包括Toolbar、BottomNavigationView等)的简化实现

可通过NavigationUI.setupWithNavController方法,绑定导航栏与Navigation。替换原有的ViewPage+Fragment等写法。

3-3:Safe Args - 类型安全的传值

1、默认情况下,你可以使用navigate(@IdRes int resId, @Nullable Bundle args)方式传值,还是一个Bundle方式的传值。

在目的页面,如果是Activity,则通过getIntent()取值。如果是Fragment,则通过getArguments()取值。

2、Safe Args方式,需要做一些额外工作。

1、在最外层的build中添加插件navigation-safe-args-gradle-plugin
dependencies {
            def nav_version = "2.3.0-alpha01"
            classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
} 
2、在应用层的build中,应用插件apply plugin: "androidx.navigation.safeargs" 
3、在nav_graph.xml文件中,可以对每个页面,新增参数。可通过手写,也可通过attribute中配置添加。
4、重新同步并编译工程。假设在CFragment中添加参数,格式如下,会指定参数的类型:
<fragment
        android:id="@+id/CFragment"
        android:name="com.test.jetpackdemo.CFragment"
        android:label="fragment_c"
        tools:layout="@layout/fragment_c">

        <argument
            android:name="str_inC"
            app:argType="string" />
       
    </fragment>

   5、当存在AFragment指向外界的action时,AFragment才会根据插件生成对应的 Directions。如:AFragmentDirections。

    假设AFragment指向CFragment,CFragment中有str_inC,类型是String。

    那么可以通过:

    传值:

AFragmentDirections.ActionAFragmentToCFragment argsInfo = AFragmentDirections.actionAFragmentToCFragment("test"); Navigation.findNavController(nav1).navigate(R.id.action_AFragment_to_CFragment,argsInfo.getArguments());

    取值:

CFragmentArgs.fromBundle(getArguments()).getStrInC();

  

 Safe Args方式,因为已经指定了参数类型,并且只能按该类型来传值,所以是类型安全的。只是过于繁琐,非必要情况不建议使用。

Navigation的基本使用已完成。

猜你喜欢

转载自blog.csdn.net/yangzhaomuma/article/details/106315770