在一個同系列目標的操作流程中,將各個 fragment 歸類在同一個 navigation 內非常有用,可以幫助我們分類、可讀性與維護性也更高。
例如:一開啟 App 時判斷是否登入,如果沒有登入則導航至另一個登入流程的 navigation。
1.在導航編輯器中,按住Shift鍵,點擊想要歸類在同一個 navigation 的 fragment
2.右鍵 Move to Nested Graph -> New Graph
這時候就會在 navigation 底下多一層嵌套的 navigation,並指定 startDestination
。
<?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_main"
app:startDestination="@id/page3Fragment">
<navigation
android:id="@+id/navigation_login"
app:startDestination="@id/loginPage1Fragment">
<fragment
android:id="@+id/loginPage1Fragment"
.
.
.
</fragment>
<fragment
android:id="@+id/loginPage2Fragment"
.
.
.
</fragment>
</navigation>
使用時把這個整包的 navigation 當成是一個 fragment 來用,切換到這個 navigation 時自然也是從他的 startDestination
當作起始頁。
<fragment
android:id="@+id/page3Fragment"
android:name="com.guanhong.mvvmpractice.view.navigation.FragmentThree"
android:label="fragment_page3"
tools:layout="@layout/fragment_navigation_three">
<action
android:id="@+id/action_page3Fragment_to_navigation_login"
app:destination="@id/navigation_login" />
</fragment>
<navigation
android:id="@+id/navigation_login"
app:startDestination="@id/loginPage1Fragment">
<fragment
android:id="@+id/loginPage1Fragment"
.
.
.
</fragment>
<fragment
android:id="@+id/loginPage2Fragment"
.
.
.
</fragment>
</navigation>
textView.setOnClickListener {
Navigation
.findNavController(it)
.navigate(R.id.action_page3Fragment_to_navigation_login)
}
使用 navigation 要如何在 fragments 之間傳遞參數呢
之前換頁的代碼
Navigation
.findNavController(it)
.navigate(R.id.action_page2_to_action_page3)
navigate
點進去看源碼,用的都是這個
public void navigate(@IdRes int resId) {
navigate(resId, null);
}
往下拉會發現,這個 navigate
用多形寫了很多方法,其中一個就是可以用來丟 bundle
的方法。
public void navigate(@IdRes int resId, @Nullable Bundle args) {
navigate(resId, args, null);
}
所以可以像平常丟參數的方法一樣丟 bundle 進去
val bundle = Bundle()
bundle.putString("userName", userName)
Navigation
.findNavController(it)
.navigate(R.id.action_page2_to_action_page3, bundle)
獲得數據
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
var userName: String? = null
arguments?.let {
userName = it.getString("userName")
}
}
也可以直接在 fragment 標籤內加上 argument 標籤,就可以設定 defaultValue
<fragment
android:id="@+id/page1Fragment"
android:name="com.guanhong.mvvmpractice.view.navigation.FragmentOne"
android:label="fragment_page1"
tools:layout="@layout/fragment_navigation_one">
<action
android:id="@+id/action_page1_to_action_page2"
app:destination="@id/page2Fragment" />
<argument
android:name="userName"
android:defaultValue="user name"
app:argType="string" />
</fragment>
這個 argument
是代表這個 fragment 會接受到的 argument
,不是要傳出去的。
Navigation 算是一個相當方便的組件,能夠輕鬆的以圖像的方式處理好,fragment 之間的換頁流程,內建轉場動畫能使換頁更加流暢,切換 fragment 的動作只需要一行代碼就搞定,實在太方便啦!
唯一的缺點就是預設的切換方式是用 replace
,要換成 show
、hide
的話就必需自已客製 NavController
,就會比較麻煩一點。
有任何問題或講得不清楚的地方歡迎留言和我討論。
更歡迎留言糾正我任何說錯的地方!