Jetpack 之 Navigation 初探

簡(jiǎn)介

Google 2018 I/O大會(huì)上,Google正式推出了Android/Jetpack撕彤,其中隆重推出了一個(gè)新的架構(gòu)組件:Navigation

Google 官方介紹:

作為構(gòu)建您的應(yīng)用內(nèi)界面的框架涣觉,重點(diǎn)是讓單 Activity 應(yīng)用成為首選架構(gòu)匙瘪。利用 Navigation 組件對(duì) Fragment 的原生支持乌庶,您可以獲得架構(gòu)組件的所有好處(例如生命周期和 ViewModel)怔毛,同時(shí)讓此組件為您處理 FragmentTransaction 的復(fù)雜性。此外促王,Navigation組件還可以讓您聲明我們?yōu)槟幚淼霓D(zhuǎn)場(chǎng)犀盟。它可以自動(dòng)構(gòu)建正確的“向上”和“返回”行為,包含對(duì)深層鏈接的完整支持蝇狼,并提供了幫助程序阅畴,用于將導(dǎo)航關(guān)聯(lián)到合適的 UI 小部件,例如抽屜式導(dǎo)航欄和底部導(dǎo)航迅耘。

集成環(huán)境

Android Studio 3.2+
下載地址:https://developer.android.com/studio/preview

添加依賴

Step-1:

repositories 添加 Google 倉(cāng)庫(kù)和 classpath

  buildscript {
    repositories {
        google()
    }
    dependencies {
        classpath "android.arch.navigation:navigation-safe-args-gradle-plugin:1.0.0-alpha01"
    }
}

Step-2:

添加 Navigation 庫(kù)的依賴

dependencies {
    def nav_version = "1.0.0-alpha01"

    implementation "android.arch.navigation:navigation-fragment:$nav_version" // use -ktx for Kotlin
    implementation "android.arch.navigation:navigation-ui:$nav_version" // use -ktx for Kotlin

    // optional - Test helpers
    androidTestImplementation "android.arch.navigation:navigation-testing:$nav_version" // use -ktx for Kotlin
}

新建 Navigation

  • 新建 Android 項(xiàng)目贱枣。
  • res 目錄右鍵 New->New Resource File,彈出 New Resource File 的對(duì)話框颤专。
  • 填寫(xiě) File Name 如:nav_graph纽哥,Resource type 選擇 Navigation,點(diǎn)擊OK( Android Studio 3.3新建項(xiàng)目會(huì)自動(dòng)生成該目錄)血公。

以上操作會(huì)在 res 下生成一個(gè) navigation 目錄昵仅,目錄下有剛才新建的 nav_graph.xml 文件,打開(kāi)該文件累魔,內(nèi)容是一個(gè) navigation 的空節(jié)點(diǎn)摔笤。和布局文件類(lèi)似,AndroidStudio 界面上有垦写。

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android">

</navigation>

使用 Navigation

Step-1:

新建兩個(gè) Fragment:FragmentA吕世、FragmentB 對(duì)應(yīng)布局為 fragment_a.xml、fragment_b.xml

Step-2:

打開(kāi) nav_graph.xml梯投,底部選擇 Design 選項(xiàng)卡命辖,點(diǎn)擊 New Destination (左上角 + ) 按鈕,在彈窗中選擇
fragment_a.xml分蓖、fragment_b.xml尔艇,或選擇 Create blank destination 新建Fragment.之后選顯示如下界面:

image

此時(shí) nav_graph.xml 內(nèi)容如下,點(diǎn)擊 Text 切換

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:tools="http://schemas.android.com/tools"
    app:startDestination="@id/fragmentA">

    <fragment
        android:id="@+id/fragmentA"
        android:name="com.halove.jetpackdmeo.FragmentA"
        android:label="fragment_a"
        tools:layout="@layout/fragment_a" >
    </fragment>
    <fragment
        android:id="@+id/fragmentB"
        android:name="com.halove.jetpackdmeo.FragmentB"
        android:label="fragment_b"
        tools:layout="@layout/fragment_b" />
</navigation>

Step-3:

在 Activity 布局里添加 NavHostFragment (關(guān)于 NavHostFragment 可以看這篇博客么鹤,解釋的很清楚 https://blog.csdn.net/mq2553299/article/details/80445952)

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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/my_nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph" />

</android.support.constraint.ConstraintLayout>

app:defaultNavHost="true" 是攔截返回鍵终娃,即將返回托管給NavHostFragment處理。否則返回直接退出當(dāng)前 Activity 蒸甜。app:navGraph="@navigation/nav_graph"將 NavHostFragment 跟我們剛才創(chuàng)建的 navigation 關(guān)聯(lián)棠耕。
然后重新打開(kāi) nav_graph.xml 會(huì)發(fā)現(xiàn)在 HOST 下面就會(huì)顯示我們關(guān)聯(lián)的 activity:

image

Step-4:

添加導(dǎo)航連接

左鍵按住 fragment 右側(cè)中間的圓圈然后拖動(dòng)到要導(dǎo)航的 fragment 然后松手

image

切換到 Text 模式下,發(fā)現(xiàn)在 fragment 標(biāo)簽里添加了一個(gè) action 節(jié)點(diǎn)柠新,action 添加了一個(gè) id 和 destination 窍荧,destination 就是我們要導(dǎo)航到的 fragment。

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:tools="http://schemas.android.com/tools"
    app:startDestination="@id/fragmentA">

    <fragment
        android:id="@+id/fragmentA"
        android:name="com.halove.jetpackdmeo.FragmentA"
        android:label="fragment_a"
        tools:layout="@layout/fragment_a" >
        <action
            android:id="@+id/action_fragmentA_to_fragmentB"
            app:destination="@id/fragmentB" />
    </fragment>
    <fragment
        android:id="@+id/fragmentB"
        android:name="com.halove.jetpackdmeo.FragmentB"
        android:label="fragment_b"
        tools:layout="@layout/fragment_b" />
</navigation>

Activity 中不需要做任何操作恨憎,只需要設(shè)置布局即可:

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.main_activity)
    }
}

在 FragmentA 中布局中添加一個(gè) Button 蕊退,點(diǎn)擊跳轉(zhuǎn)到 FragmentB :

  override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
   
        to_fragmentb_btn.setOnClickListener {
            Navigation.findNavController(it).navigate(R.id.action_fragmentA_to_fragmentB)
        }
        to_fragmentb_btn.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.action_fragmentA_to_fragmentB))
 }

使用很簡(jiǎn)單,調(diào)用 Navigation 的 findNavController 方法找到 NavController , findNavController 還有其他參數(shù)的方法大家可以自己試試咕痛,然后調(diào)用 navigate 方法痢甘,參數(shù)就是 nav_graph.xml 里 actionid ≤怨保或者直接使用 createNavigateOnClickListener.

按返回鍵會(huì)回退到上一個(gè) Fragment 塞栅,也可以調(diào)用 NavController 的 popBackStack 進(jìn)行回退

頁(yè)面?zhèn)鲄?/h2>

1 .代碼傳參

navigate 有好幾個(gè)方法,如圖所示:

image

可以使用Bundle傳參

 val bundle = Bundle()
 bundle.putString("param", "I AM FROM FRAGMENT-A")
 Navigation.findNavController(it).navigate(R.id.action_fragmentA_to_fragmentC,bundle)

2. xml 文件傳參

在 navigation 的xml的 fragment 的 action 里添加 argument 標(biāo)簽,然后使用生成的對(duì)應(yīng)的 Agrs 或者 Directions 來(lái)傳遞參數(shù)腔丧,需要在 build.gradle 中添加 apply plugin: 'androidx.navigation.safeargs'

<fragment
    android:id="@+id/fragmentB"
    android:name="com.halove.jetpackdmeo.FragmentB"
    android:label="fragment_b"
    tools:layout="@layout/fragment_b" >
    <argument android:name="text" android:defaultValue="Hello" app:type="string"/>
</fragment>

傳參:

FragmentBArgs 和 FragmentADirections 都是自動(dòng)生成的放椰,F(xiàn)ragmentBArgs 是根據(jù)fragment 節(jié)點(diǎn)下的 argument 節(jié)點(diǎn)生成的,F(xiàn)ragmentADirections 是根據(jù) action 生成的

//使用FragmentBArgs
val bundle = FragmentBArgs.Builder().setText("Hello World").build().toBundle()
Navigation.findNavController(it).navigate(R.id.action_fragmentA_to_fragmentB, bundle)

//使用FragmentADirections
val direction = FragmentADirections.action_fragmentA_to_fragmentB().setText("Hello World")
Navigation.findNavController(it).navigate(direction)

3. 參數(shù)接收

val text = FragmentBArgs.fromBundle("key").text
//或
val text =  arguments!!["key"].toString()

轉(zhuǎn)場(chǎng)動(dòng)畫(huà)

轉(zhuǎn)場(chǎng)動(dòng)畫(huà)可以直接在 action 里面使用動(dòng)畫(huà)文件:

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    app:startDestination="@id/fragmentA">

    <fragment
        android:id="@+id/fragmentA"
        android:name="com.halove.jetpackdmeo.FragmentA"
        android:label="fragment_a"
        tools:layout="@layout/fragment_a" >
        <action
            android:id="@+id/action_fragmentA_to_fragmentB"
            app:destination="@id/fragmentB"
            app:enterAnim="@anim/slide_in_right"
            app:exitAnim="@anim/slide_out_left"
            app:popEnterAnim="@anim/slide_in_left"
            app:popExitAnim="@anim/slide_out_right"/>
    </fragment>
    <fragment
        android:id="@+id/fragmentB"
        android:name="com.halove.jetpackdmeo.FragmentB"
        android:label="fragment_b"
        tools:layout="@layout/fragment_b" >
        <argument android:name="text" android:defaultValue="Hello" app:type="string"/>
    </fragment>
</navigation>

Demo

附上使用小 Demo

地址:https://github.com/wanglejun/NavigationDemo.git

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末愉粤,一起剝皮案震驚了整個(gè)濱河市砾医,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌衣厘,老刑警劉巖如蚜,帶你破解...
    沈念sama閱讀 217,734評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異影暴,居然都是意外死亡错邦,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,931評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門(mén)型宙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)撬呢,“玉大人,你說(shuō)我怎么就攤上這事妆兑』昀梗” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,133評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵搁嗓,是天一觀的道長(zhǎng)芯勘。 經(jīng)常有香客問(wèn)我,道長(zhǎng)腺逛,這世上最難降的妖魔是什么借尿? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,532評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮屉来,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘狈癞。我一直安慰自己茄靠,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,585評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布蝶桶。 她就那樣靜靜地躺著慨绳,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上脐雪,一...
    開(kāi)封第一講書(shū)人閱讀 51,462評(píng)論 1 302
  • 那天厌小,我揣著相機(jī)與錄音,去河邊找鬼战秋。 笑死璧亚,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的脂信。 我是一名探鬼主播癣蟋,決...
    沈念sama閱讀 40,262評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼狰闪!你這毒婦竟也來(lái)了疯搅?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,153評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤埋泵,失蹤者是張志新(化名)和其女友劉穎幔欧,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體丽声,經(jīng)...
    沈念sama閱讀 45,587評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡礁蔗,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,792評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了恒序。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瘦麸。...
    茶點(diǎn)故事閱讀 39,919評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖歧胁,靈堂內(nèi)的尸體忽然破棺而出滋饲,到底是詐尸還是另有隱情,我是刑警寧澤喊巍,帶...
    沈念sama閱讀 35,635評(píng)論 5 345
  • 正文 年R本政府宣布屠缭,位于F島的核電站,受9級(jí)特大地震影響崭参,放射性物質(zhì)發(fā)生泄漏呵曹。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,237評(píng)論 3 329
  • 文/蒙蒙 一何暮、第九天 我趴在偏房一處隱蔽的房頂上張望奄喂。 院中可真熱鬧,春花似錦海洼、人聲如沸跨新。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,855評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)域帐。三九已至赘被,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間肖揣,已是汗流浹背民假。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,983評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留龙优,地道東北人羊异。 一個(gè)月前我還...
    沈念sama閱讀 48,048評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像陋率,于是被迫代替她去往敵國(guó)和親球化。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,864評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容