Navigation
Navigation簡介
導航架構組件簡化了Android應用程序中導航的實現,通過在xml中添加元素並指定導航的起始和目的地,從而在Fragment之間建立連接,在Activity中調用xml中設置的導航action實現跳轉界面到目的地。簡單來說,它和之前在活動中調用startActivity的區別就類似於代碼佈局和xml中layout佈局一樣,既簡單又可視化。
Navigation設置操作
在項目中設置Navigation
-
在項目中開啓Navigation支持
-
添加組件依賴
def nav_version = "1.0.0-alpha06" 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編輯器
- 創建資源文件
在 res 目錄右擊,選擇 New > Android Resource File,Resource type 選擇 Navigation。 - 創建destination(目的地)
創建destination的方式分爲兩種
- 在Navigation編輯器中Create blank destination,如下圖所示:
這種方式會在一級路徑下創建Fragment。
- 外部創建後,在編輯器中引入
可引入Activity,Fragment等組件。
-
配置navigation
android:name
,指定Fragment路徑;tools:layout
,指定佈局文件;app:startDestination
,指定起始項。
<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_test" app:startDestination="@id/test1Fragment"> <fragment android:id="@+id/test1Fragment" android:name="com.sanmen.bluesky.jetpackdemo.Test1Fragment" android:label="fragment_test1" tools:layout="@layout/fragment_test1"> </fragment> ... </navigation>
在Activity中引用
-
第一種方式是在 xml 裏寫 fragment。如下:
<android.support.constraint.ConstraintLayout ...> ... <fragment android:layout_width="0dp" android:layout_height="0dp" android:id="@+id/fragment" android:name="androidx.navigation.fragment.NavHostFragment" app:navGraph="@navigation/nav_test" app:defaultNavHost="true" ...> </android.support.constraint.ConstraintLayout>
android:name
,指定 NavHostFragment,它實現了 NavHost,這是一個用於放置管理 destination 的空視圖。app:navGraph
,關聯 NavHostFragment 和 nav_graph.xml 。app:defaultNavHost
,指定 NavHostFragment 可以攔截處理返回鍵。
-
第二種方式是通過代碼創建 NavHostFragment,修改 Activity 的 xml:
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout ... > <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/frame_layout" /> </android.support.constraint.ConstraintLayout>
然後再Activity中引入:
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val finalHost = NavHostFragment.create(R.navigation.nav_test) supportFragmentManager.beginTransaction() .replace(R.id.frame_layout, finalHost) .setPrimaryNavigationFragment(finalHost) // 等價於 xml 中的 app:defaultNavHost="true" .commit() }
Navigation連接
-
連接destination
一種方式,在編輯器可視界面中拖線連接。
另一種方式,在xml代碼界面,爲fragment添加。兩種方式原理相同。
-
處理跳轉
Navigation的跳轉通過NavController對象來實現。獲取方式如下:NavHostFragment.findNavController(Fragment)
Navigation.findNavController(Activity, @IdRes int viewId)
Navigation.findNavController(View)
調用 NavController 的
navigate
方法執行跳轉,navigate 的參數可以是一個destination
(這裏就是 fragment 在導航圖 nav_graph 中的 id),也可以是action
的 id。override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) btnToBlank!!.setOnClickListener { //跳轉方式1 Navigation.findNavController(getView()!!) .navigate(R.id.action_test1Fragment_to_blankFragment) } btnToPaging!!.setOnClickListener { //跳轉方式2 NavHostFragment.findNavController(this) .navigate(R.id.action_test1Fragment_to_pagingActivity) } }
-
添加跳轉動畫
點擊目標箭頭(提示頁面指向的箭頭),並在屬性面板中設置動畫Transitions。
如圖,在text1Fragment到blankFragment之間的跳轉添加一個enter動畫,在代碼界面會發生如下改變(指定了當前Action的app:enterAnim屬性):... <fragment android:id="@+id/test1Fragment" android:name="com.sanmen.bluesky.jetpackdemo.Test1Fragment" android:label="fragment_test1" tools:layout="@layout/fragment_test1"> <action android:id="@+id/action_test1Fragment_to_blankFragment" app:destination="@id/blankFragment" app:enterAnim="@anim/nav_default_enter_anim"/> ... </fragment>
-
傳遞數據
- 要跳轉到BlankFragment,要往 BlankFragment裏帶數據,在目的 Fragment 裏添加 < argument>
<navigation xmlns:android="http://schemas.android.com/apk/res/android" ... > <fragment android:id="@+id/blankFragment" android:name="com.sanmen.bluesky.jetpackdemo.BlankFragment" android:label="fragment_blank" tools:layout="@layout/fragment_blank"> <action android:id="@+id/action_blankFragment_to_liveDataActivity" app:destination="@id/liveDataActivity" app:enterAnim="@anim/nav_default_enter_anim"/> <argument android:name="value" android:defaultValue="defaultValue=1" /> </fragment> </navigation>
- Test1Fragment添加數據
... btnToBlank!!.setOnClickListener { //利用Bundle對象發送數據 val bundle = Bundle() bundle.putString("name","Blank") bundle.putInt("year",1210) //跳轉方式1 Navigation.findNavController(getView()!!) .navigate(R.id.action_test1Fragment_to_blankFragment,bundle) } ...
- BlankFragment 獲取數據
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View? { ... //// 在接收的代碼中,使用該 getArguments()方法檢索包並使用其內容 arguments?.let {bundle -> var name = bundle.getString("name") var year = bundle.getInt("year") tvValue!!.text = "name:$name,year:$year" } ... }
- 要跳轉到BlankFragment,要往 BlankFragment裏帶數據,在目的 Fragment 裏添加 < argument>
問題記錄
- fragment中默認創建的OnFragmentInteractionListener 接口用於處理Fragment之間的通信,基於共同的Activity爲橋樑,並在Activity中實現OnFragmentInteractionListener 接口。
interface OnFragmentInteractionListener { // TODO: Update argument type and name fun onFragmentInteraction(uri: Uri) }