在今年的 IO 大會上,發(fā)布了一套叫 Android Jetpack 的程序庫他去。Android Jetpack 里的組件大部分我們都接觸過了,其中也有一些全新的組件,其中一個(gè)就是 Navigation咕幻。
簡介
Navigation 是用來管理 APP 里頁面跳轉(zhuǎn)的。起初顶霞,我以為它是用來代替 startActivity 的肄程,但其實(shí)并不是,大家往下看就知道它的作用了。
另外蓝厌,iOS 的同學(xué)可能會有似曾相識的感覺玄叠,Navigation 應(yīng)該是有借鑒 Storyboard 的。
使用
我們先來看看 Navigation 的實(shí)現(xiàn)過程拓提。
添加依賴
首先诸典,需要使用 Android Studio 3.2 以上版本才能使用 Navigation。
在 build.gradle 中添加依賴:
implementation "android.arch.navigation:navigation-fragment:$nav_version"
implementation "android.arch.navigation:navigation-ui:$nav_version"
創(chuàng)建 navigation xml 文件
使用 「Android Resource File」創(chuàng)建 xml 文件的時(shí)候崎苗,可以看到在類型里狐粱,多了一個(gè) Navigation 的選項(xiàng):
創(chuàng)建成功后,就來到了文章開頭的那個(gè)一個(gè)可視化的操作界面胆数。點(diǎn)擊左上角的添加小圖標(biāo)肌蜻,會出現(xiàn) Activity 和 Fragment,我們這里添加兩個(gè) Activity 和兩個(gè) Fragment:
配置 Action
Fragment 的右邊有個(gè)小圓圈必尼,點(diǎn)擊并拖到另一個(gè)頁面蒋搜,這樣我們就給這個(gè) Fragment 添加了一個(gè)跳轉(zhuǎn)行為,也就是 Action判莉。
但是可以發(fā)現(xiàn)豆挽,Activity 的右邊是沒有這個(gè)小圓圈的,所以 Navigation 并不能處理從 Activity 發(fā)起的跳轉(zhuǎn)帮哈。
左上角有個(gè)小房子的是顯示的第一個(gè)頁面,但由于 Activity 無法發(fā)起跳轉(zhuǎn)锰镀,所以這里把 MainActivity 刪除娘侍,把 MainFragment 作為主頁面,并給它添加跳轉(zhuǎn)到 SecondFragment 和 SecondActivity 的 Action:
自動(dòng)生成的 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"
app:startDestination="@id/mainFragment">
<fragment
android:id="@+id/mainFragment"
android:name="com.example.navigation.MainFragment"
android:label="fragment_main"
tools:layout="@layout/fragment_main">
<action
android:id="@+id/action_mainFragment_to_secondFragment"
app:destination="@id/secondFragment"
app:enterAnim="@anim/slide_in_right" />
<action
android:id="@+id/action_mainFragment_to_secondActivity"
app:destination="@id/secondActivity" />
</fragment>
<fragment
android:id="@+id/secondFragment"
android:name="com.example.navigation.SecondFragment"
android:label="fragment_second"
tools:layout="@layout/fragment_second" />
<activity
android:id="@+id/secondActivity"
android:name="com.example.navigation.SecondActivity"
android:label="activity_second"
tools:layout="@layout/activity_second" />
</navigation>
布局中添加 Fragment
現(xiàn)在泳炉,我們第一個(gè)頁面是 MainFragment憾筏,而 Fragment 需要 Activity 作為容器,修改 MainActivity 的布局:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
android:id="@+id/fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav" />
</FrameLayout>
其中有三個(gè)屬性需要注意花鹅。使用 android:name 指定 Fragment 的類型為 NavHostFragment氧腰,使用 app:navGraph 指定 Navigation 文件。app:defaultNavHost="true" 的作用是刨肃,讓 Navigation 處理返回事件古拴,點(diǎn)返回按鈕時(shí)并不是返回上一個(gè) Activity,而是返回上一個(gè)「頁面」之景,上一個(gè)「頁面」有可能是 Activity斤富,也可能是 Fragment。
至此锻狗,Navigation 的簡單配置就算完成了满力,接下來看如何使用它焕参。
配置跳轉(zhuǎn)
在 Navigation 里,頁面的跳轉(zhuǎn)是交給 NavController 來處理的油额,獲取 NavController 的方法有這么三種:
NavHostFragment.findNavController(Fragment)
Navigation.findNavController(Activity, @IdRes int viewId)
Navigation.findNavController(View)
拿到后叠纷,通過 navigate 方法,通過傳入 Action 的 id潦嘶,實(shí)現(xiàn)跳轉(zhuǎn)涩嚣,比如:
NavHostFragment
.findNavController(this)
.navigate(R.id.action_firstFragment_to_secondFragment)
在簡單配置了兩個(gè)跳轉(zhuǎn)后,看一下目前的效果:
傳參
頁面的跳轉(zhuǎn)少不了數(shù)據(jù)的傳遞掂僵,使用 Navigation航厚,和我們原來的跳轉(zhuǎn)一樣,可以通過 Bundle 來傳遞參數(shù):
val bundle = Bundle()
bundle.putString("name", "SouthernBox")
NavHostFragment
.findNavController(this)
.navigate(R.id.action_firstFragment_to_secondFragment, bundle)
如果跳轉(zhuǎn)到 Activity锰蓬,可以從 intent.extras 獲取到 bundle幔睬,如果是 Fragment,則從 arguments 獲取到芹扭。
此外麻顶,還可以在 Navigation 的 xml 文件中配置傳參,但這種方式目前支持的數(shù)據(jù)類型比較少舱卡,連 boolean 都不支持辅肾,而且我還碰到了 bug,所以目前不建議用轮锥。
轉(zhuǎn)場動(dòng)畫
如果需要自定義的頁面轉(zhuǎn)場動(dòng)畫矫钓,使用 Navigation 可以很方便的實(shí)現(xiàn)。
這里舉個(gè)例子交胚,比如我們需要一個(gè)從右向左切入的過場動(dòng)畫份汗,先創(chuàng)建這個(gè)動(dòng)畫的 xml 文件:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="600"
android:fromXDelta="100%"
android:toXDelta="0" />
</set>
然后我們回到 Navigation 的可視化編輯頁面來,點(diǎn)擊跳轉(zhuǎn)的線蝴簇,右邊會出現(xiàn)過場動(dòng)畫的配置選項(xiàng),將 xxxx 設(shè)為剛才創(chuàng)建的動(dòng)畫:
這么簡單就搞定了匆帚,效果如下:
Navigation 的使用介紹就到這里熬词。
思考
你可能已經(jīng)明白,Navigation 主要是用來處理 Fragment 的跳轉(zhuǎn)吸重,所以說它并不是用來代替 startActivity互拾,而是用來代替 FragmentTransaction 的相關(guān)操作。
在官方文檔里嚎幸,可以看到一個(gè)將傳統(tǒng)跳轉(zhuǎn)遷移到 Navigation 的建議颜矿。我簡單理解為,將原本兩個(gè) Activity 之間的跳轉(zhuǎn)嫉晶,逐漸修改為使用一個(gè) Activity 作為容器骑疆,用兩個(gè) Fragment 作為頁面跳轉(zhuǎn)田篇。
看到這里,我聯(lián)想到了在去年箍铭,Jake Wharton(目前在谷歌)有這么一個(gè)有爭議的言論:
“一個(gè) APP 只需要一個(gè) Activity泊柬。”
在過去诈火,要實(shí)現(xiàn)這種方式兽赁,就需要去解決復(fù)雜的 Fragment 堆棧處理,而且早期的 Fragment 坑比較多冷守,處理不好容易出現(xiàn)頁面穿透等問題〉堆拢現(xiàn)在 Navigation 恰好解決了這些問題。
這一切聯(lián)系起來拍摇,是不是能說明官方間接支持了「少用 Activity 多用 Fragment」的做法亮钦?你怎么看?