簡介
Google 2018 I/O大會上,Google正式推出了Android/Jetpack,其中隆重推出了一個新的架構元件:Navigation
Google 官方介紹:
作為構建您的應用內介面的框架,重點是讓
單 Activity 應用
成為首選架構。利用 Navigation 元件對 Fragment 的原生支援,您可以獲得架構元件的所有好處(例如生命週期和 ViewModel),同時讓此元件為您處理 FragmentTransaction 的複雜性。此外,Navigation元件還可以讓您宣告我們為您處理的轉場。它可以自動構建正確的“向上”和“返回”行為,包含對深層連結的完整支援,並提供了幫助程式,用於將導航關聯到合適的 UI 小部件,例如抽屜式導航欄和底部導航。
整合環境
Android Studio 3.2+ 下載地址:developer.android.com/studio/prev…
新增依賴
Step-1:
repositories 新增 Google 倉庫和 classpath
buildscript {
repositories {
google()
}
dependencies {
classpath "android.arch.navigation:navigation-safe-args-gradle-plugin:1.0.0-alpha01"
}
}
複製程式碼
Step-2:
新增 Navigation 庫的依賴
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 專案
- 在
res
目錄右鍵 New->New Resource File,彈出New Resource File
的對話方塊。 - 填寫 File Name 如:nav_graph,Resource type 選擇
Navigation
,點選OK(Android Studio 3.3新建專案會自動生成該目錄)。
以上操作會在
res
下生成一個navigation
目錄,目錄下有剛才新建的nav_graph.xml
檔案,開啟該檔案,內容是一個navigation
的空節點。和佈局檔案類似,AndroidStudio 介面上有。
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android">
</navigation>
複製程式碼
使用 Navigation
Step-1:
新建兩個 Fragment:FragmentA、FragmentB 對應佈局為 fragment_a.xml、fragment_b.xml
Step-2:
開啟 nav_graph.xml
,底部選擇 Design 選項卡,點選 New Destination
(左上角 + ) 按鈕,在彈窗中選擇
fragment_a.xml
、fragment_b.xml
,或選擇 Create blank destination
新建Fragment.之後選顯示如下介面:
此時
nav_graph.xml
內容如下,點選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
(關於 NavHostFragment 可以看這篇部落格,解釋的很清楚 blog.csdn.net/mq2553299/a…)
<?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處理。否則返回直接退出當前 Activity 。app:navGraph="@navigation/nav_graph"
將 NavHostFragment 跟我們剛才建立的 navigation 關聯。
然後重新開啟 nav_graph.xml 會發現在 HOST 下面就會顯示我們關聯的 activity:
Step-4:
新增導航連線
左鍵按住 fragment 右側中間的圓圈然後拖動到要導航的 fragment 然後鬆手
切換到 Text 模式下,發現在 fragment 標籤裡新增了一個 action 節點,action 新增了一個 id 和 destination ,destination 就是我們要導航到的 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 中不需要做任何操作,只需要設定佈局即可:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.main_activity)
}
}
複製程式碼
在 FragmentA 中佈局中新增一個 Button ,點選跳轉到 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))
}
複製程式碼
使用很簡單,呼叫 Navigation 的 findNavController 方法找到 NavController , findNavController 還有其他引數的方法大家可以自己試試,然後呼叫 navigate 方法,引數就是 nav_graph.xml 裡
action
的id
。或者直接使用 createNavigateOnClickListener.
按返回鍵會回退到上一個 Fragment ,也可以呼叫 NavController 的 popBackStack 進行回退
頁面傳參
1 .程式碼傳參
navigate 有好幾個方法,如圖所示:
可以使用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
標籤,然後使用生成的對應的 Agrs 或者 Directions 來傳遞引數,需要在 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 都是自動生成的,FragmentBArgs 是根據fragment 節點下的 argument 節點生成的,FragmentADirections 是根據 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. 引數接收
val text = FragmentBArgs.fromBundle("key").text
//或
val text = arguments!!["key"].toString()
複製程式碼
轉場動畫
轉場動畫可以直接在 action 裡面使用動畫檔案:
<?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