Navigation深入浅出,到出神入化,再到实战改造

思考几个问题:

  1. 可以在代码中用Bundle传递参数,为什么要在XML去配置
  2. XML中的参数标签,只能设置和读取,无法在XML中跳转是附带传过去,如B页面要求传入name:String,于是在<Argment>标签中配置,但A去跳转时,无法在XML中传入,只能在代码中定义参数名称和值,那么XML的参数还有何意义?有什么实用的场景?
  3. navigationUp和popBackStack()回退上一级时有什么区别,该如何正确使用
  4. 跳转时 有时用的是Action的ID,有时用的是Fragment的ID 他俩到底在什么场景下,区分该将哪个传入方法作为参数

使用和核心方法

1.创建NavGraph

图片.png
<?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/home_fragment">
    <fragment
        android:id="@+id/home_fragment"
        android:name="org.devio.proj.navigationdemo.HomeFragment"
        android:label="@string/hello_blank_fragment"
        tools:layout="@layout/fragment_home">
        <action
            android:id="@+id/home_to_other"
            app:destination="@id/other_fragment"
            app:enterAnim="@anim/fade_in"
            app:exitAnim="@anim/fade_out" />
    </fragment>

    <fragment
        android:id="@+id/other_fragment"
        android:name="org.devio.proj.navigationdemo.OtherFragment"
        android:label="@string/hello_blank_fragment"
        tools:layout="@layout/fragment_other">

        <action
            android:id="@+id/other_to_deeplink"
            app:destination="@id/nav_graph_to" />
        
        <argument
            android:name="home_arg_name"
            android:defaultValue="defName"
            app:argType="string"
            app:nullable="true" />

        <argument
            android:name="home_arg_age"
            android:defaultValue="99"
            app:argType="integer" />
        <argument
            android:name="home_arg_mode"
            app:argType="org.devio.proj.navigationdemo.Model" />
        <!--        <deepLink-->
        <!--        android:id="@+id/deepLink"-->
        <!--        app:uri="www.baidu.com" />-->
        <!--        android:autoVerify="false"
                    app:action="ACTION_SEND"
                    app:mimeType="text/html"-->
    </fragment>

    <navigation
        android:id="@+id/nav_graph_to"
        android:label="SecondHome"
        app:startDestination="@id/deep_link_fragment">
        <fragment
            android:id="@+id/deep_link_fragment"
            android:name="org.devio.proj.navigationdemo.DeeplinkFragment"
            android:label="@string/hello_blank_fragment"
            tools:layout="@layout/fragment_deeplink">

            <action
                android:id="@+id/deeplink_to_home"
                app:popUpTo="@id/home_fragment" />
        </fragment>
        <fragment
            android:id="@+id/settingFragment"
            android:name="org.devio.proj.navigationdemo.SettingFragment"
            android:label="fragment_setting"
            tools:layout="@layout/fragment_setting" />
    </navigation>
</navigation>

==navigation== :视图导航的根部标签, ==app:startDestination="@id/home_fragment"== 指定以哪个页面为首页。<navigation> 标签下包含3中子标签。:

<activity></activity>  支持Activity 跳转
<dialog></dialog>      支持 dialogFragment 跳转
<fragment></fragment>  支持fragment 跳转

出以上三种跳转类型外,==</navigation>== 标签下还支持嵌套操作。

 <navigation>
        <navigation>
            
        </navigation>
        
         <include  >// 嵌套另一个nav_graph ,注意:
         这个布局只能是<navigation>为根节点的布局

        </include>
    </navigation>

以Fragment为例,创建3个Fragment实例,分别为HomeFragment,OtherFragment,DeeplinkFragment。


<?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/home_fragment">
    <fragment
        android:id="@+id/home_fragment"
        android:name="org.devio.proj.navigationdemo.HomeFragment"
        android:label="@string/hello_blank_fragment"
        tools:layout="@layout/fragment_home">
    </fragment>

    <fragment
        android:id="@+id/other_fragment"
        android:name="org.devio.proj.navigationdemo.OtherFragment"
        android:label="@string/hello_blank_fragment"
        tools:layout="@layout/fragment_other">
    </fragment>

    <navigation
        android:id="@+id/nav_graph_to"
        android:label="SecondHome"
        app:startDestination="@id/deep_link_fragment">
        <fragment
            android:id="@+id/deep_link_fragment"
            android:name="org.devio.proj.navigationdemo.DeeplinkFragment"
            android:label="@string/hello_blank_fragment"
            tools:layout="@layout/fragment_deeplink">

            <action
                android:id="@+id/deeplink_to_home"
                app:popUpTo="@id/home_fragment" />
        </fragment>
        <fragment
            android:id="@+id/settingFragment"
            android:name="org.devio.proj.navigationdemo.SettingFragment"
            android:label="fragment_setting"
            tools:layout="@layout/fragment_setting" />
    </navigation>
    
</navigation>

id 当前节点的唯一标识

name <fragment/> 节点对应的Fragment全类名

label 节点说明,当与BottomNavigationView组合使用时,字符串内容会成为页面的title

tools:layout coding时,查看界面内容


2.节点下参数配置说明

==注:== 节点的含义,即表示 <Activity> <Fragment>,<DialogFragment>

图片.png

点击右上角Design,进入Navigation,视图导航编辑页面。左侧为添加一个
图片.png

新节点,
图片.png
设置某个节点,为首页第一个展示节点。

==右侧是为节点添加支持的属性:==

图片.png

2.1 跳转当前页面所需参数 (Argments)

跳转,回退当前节点所需要的参数。

Name: 参数名称,等同于intent.getString(key,value)中的Key
Type: 参数类型
Array: 是否是数组(String[])
Nullable: 是否可以为空
Default Value 为空的时的默认值

更多支持的参数类型:

图片.png

2.2 跳转路由动作 (Action)

图片.png

ID 当前跳转动作节点的唯一标识,后续在代码中调用navController.navigation(R.id.ID)会用到,即执行当前配置的Action,同时也可使用想要跳转目标页的ID
From 所配置的当前节点,点击给那个节点配置,默认就是哪个。选中后不可更改
Destination 跳转的目标节点,即那个Fragment
enter:进入动画
Exit :退出动画
Pop Enter : 上一节点出栈当前节点的动画
Pop Exit: 上一节点回退栈到当前节点的动画

Pop To 按返回键会调用 navController.navigationUp或navController.popBackStack()时,想回退定向到那个节点

Inclusive: 很重要 多次出现。加入A->B->C,C的Pop To为B,当Inclusive 为true,则表示B也退出,直接进入到A,false回退到B
Single Top 类似Activity的SingleInscance,管理栈中有相同的节点,则不会创建,同时栈内此节点的上面的节点,全部出栈。

2.3 Deeplink

    <deepLink
            android:id="@+id/deepLink"
            android:autoVerify="false"
            app:action="ACTION_SEND"
            app:mimeType="text/html"
            app:uri="www.baidu.com" />

理解nav_graph.xml后,在MainActivity中配置如下配置文件:

   <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" />

以上3个配置比较重要:

    app:defaultNavHost="true"
    app:navGraph="@navigation/nav_graph"
    android:name="androidx.navigation.fragment.NavHostFragment"
  
  

三个必配项。

  1. 拦截返回键的点击事件,这样Fragment就可以想Activity一样,具有回退,返回事件
  2. 配置路由XML文件,然后加载进NavHostFragment中 app:navGraph属性,对应的就是NavGraph这个类
  3. NavHostFragment是Navigation提供的默认容器,所有路由逻辑都经过这里,然后在分发出去

3. 代码实现路由跳转和方法解析

3.1 核心方法

Acitivty#findNavController() 传入navGraph id
Fragment#findNavController() 直接调用
Navigation.findNavController() 传入View

==navController.navigate()==

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

       val homeText = view.findViewById<TextView>(R.id.home_text)
       homeText.setOnClickListener {

           val model = Model("Jack", 16)
           val bundle = Bundle()
           bundle.putString("home_arg_name", "Tom")
           bundle.putInt("home_arg_age", 12)
           bundle.putParcelable("home_arg_mode", model)
//            arguments?.let {
//                it.putString("home_arg_name", "Tom")
//                it.putInt("home_arg_age", 12)
//                it.putParcelable("home_arg_mode", model)
//            }

//            val navOptions = navOptions {
//                arguments?.let {
//                    it.putString("home_arg_name", "Tom")
//                    it.putInt("home_arg_age", 12)
//                    it.putParcelable("home_arg_mode", model)
//                }
//            }
           findNavController().navigate(R.id.home_to_other, bundle)
//            findNavController().navigate(R.id.home_to_other)
//            findNavController().navigateUp()
//            findNavController().popBackStack()

       }
   }

navigate() 传入节点ID 表示路由到节点所在页面,
传入Action ID 表示执行XML <Action>中的路由规则,同时还支持Deeplink跳转

navigateUp()和popBackStack()都表示回退上页面,但navigateUp()在Deeplink的情况下 应用1a(deeplink)路由到应用2的B后navigateUp()返回到a,而popBackStack()则会返回到当前栈内的上一层(A)
另一个区别是popBackStack()支持回退到指定页面,inclusive参数,之前有提到过

bundle 设置传递参数 Options设置其他配置参数,如动画,popUpTo等,也就说,在XML中的配置,在代码中都可实现。
那么参数中的配置argument在什么场景下比较合适。答案是:一些固定配置参数。例如loginFragment。A,B页面都会进入Login页面,但它们有不同的权限,所以可以配置不同的type,且这种配置基本不会变化。

4. 源码分析

4.1 源码中出现的个各类和职责
Navigation分析图.png

下篇将从这张图入手,开始源码分析,并利用实战改造

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容