在今年的 IO 大會上,發佈了一套叫 Android Jetpack 的程序庫。Android Jetpack 裏的組件大部分咱們都接觸過了,其中也有一些全新的組件,其中一個就是 Navigation。php
Navigation 是用來管理 APP 裏頁面跳轉的。起初,我覺得它是用來代替 startActivity 的,但其實並非,你們往下看就知道它的做用了。java
另外,iOS 的同窗可能會有似曾相識的感受,Navigation 應該是有借鑑 Storyboard 的。android
咱們先來看看 Navigation 的實現過程。app
首先,須要使用 Android Studio 3.2 以上版本才能使用 Navigation。ide
在 build.gradle 中添加依賴:佈局
implementation "android.arch.navigation:navigation-fragment:$nav_version"
implementation "android.arch.navigation:navigation-ui:$nav_version"
複製代碼
使用 「Android Resource File」建立 xml 文件的時候,能夠看到在類型裏,多了一個 Navigation 的選項:gradle
建立成功後,就來到了文章開頭的那個一個可視化的操做界面。點擊左上角的添加小圖標,會出現 Activity 和 Fragment,咱們這裏添加兩個 Activity 和兩個 Fragment:動畫
Fragment 的右邊有個小圓圈,點擊並拖到另外一個頁面,這樣咱們就給這個 Fragment 添加了一個跳轉行爲,也就是 Action。ui
可是能夠發現,Activity 的右邊是沒有這個小圓圈的,因此 Navigation 並不能處理從 Activity 發起的跳轉。this
左上角有個小房子的是顯示的第一個頁面,但因爲 Activity 沒法發起跳轉,因此這裏把 MainActivity 刪除,把 MainFragment 做爲主頁面,並給它添加跳轉到 SecondFragment 和 SecondActivity 的 Action:
自動生成的 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>
複製代碼
如今,咱們第一個頁面是 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>
複製代碼
其中有三個屬性須要注意。使用 android:name 指定 Fragment 的類型爲 NavHostFragment,使用 app:navGraph 指定 Navigation 文件。app:defaultNavHost="true" 的做用是,讓 Navigation 處理返回事件,點返回按鈕時並非返回上一個 Activity,而是返回上一個「頁面」,上一個「頁面」有多是 Activity,也多是 Fragment。
至此,Navigation 的簡單配置就算完成了,接下來看如何使用它。
在 Navigation 裏,頁面的跳轉是交給 NavController 來處理的,獲取 NavController 的方法有這麼三種:
NavHostFragment.findNavController(Fragment)
Navigation.findNavController(Activity, @IdRes int viewId)
Navigation.findNavController(View)
複製代碼
拿到後,經過 navigate 方法,經過傳入 Action 的 id,實現跳轉,好比:
NavHostFragment
.findNavController(this)
.navigate(R.id.action_firstFragment_to_secondFragment)
複製代碼
在簡單配置了兩個跳轉後,看一下目前的效果:
頁面的跳轉少不了數據的傳遞,使用 Navigation,和咱們原來的跳轉同樣,能夠經過 Bundle 來傳遞參數:
val bundle = Bundle()
bundle.putString("name", "SouthernBox")
NavHostFragment
.findNavController(this)
.navigate(R.id.action_firstFragment_to_secondFragment, bundle)
複製代碼
若是跳轉到 Activity,能夠從 intent.extras 獲取到 bundle,若是是 Fragment,則從 arguments 獲取到。
此外,還能夠在 Navigation 的 xml 文件中配置傳參,但這種方式目前支持的數據類型比較少,連 boolean 都不支持,並且我還碰到了 bug,因此目前不建議用。
若是須要自定義的頁面轉場動畫,使用 Navigation 能夠很方便的實現。
這裏舉個例子,好比咱們須要一個從右向左切入的過場動畫,先建立這個動畫的 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 的可視化編輯頁面來,點擊跳轉的線,右邊會出現過場動畫的配置選項,將 xxxx 設爲剛纔建立的動畫:
這麼簡單就搞定了,效果以下:
Navigation 的使用介紹就到這裏。
你可能已經明白,Navigation 主要是用來處理 Fragment 的跳轉,因此說它並非用來代替 startActivity,而是用來代替 FragmentTransaction 的相關操做。
在官方文檔裏,能夠看到一個將傳統跳轉遷移到 Navigation 的建議。我簡單理解爲,將本來兩個 Activity 之間的跳轉,逐漸修改成使用一個 Activity 做爲容器,用兩個 Fragment 做爲頁面跳轉。
看到這裏,我聯想到了在去年,Jake Wharton(目前在谷歌)有這麼一個有爭議的言論:
「一個 APP 只須要一個 Activity。」
在過去,要實現這種方式,就須要去解決複雜的 Fragment 堆棧處理,並且早期的 Fragment 坑比較多,處理很差容易出現頁面穿透等問題。如今 Navigation 剛好解決了這些問題。
這一切聯繫起來,是否是能說明官方間接支持了「少用 Activity 多用 Fragment」的作法?你怎麼看?