Jetpack系列:應用內導航的正確使用方法
- 2019 年 10 月 7 日
- 筆記
今天小編要分享的還是Android Jetpack庫的基本使用方法,本篇介紹的內容是Jetpack Navigation組件,讓我們一起學習,為完成年初制定的計劃而努力吧!
***
組件介紹
導航,是指提供用戶在應用程式中的不同內容之間進行瀏覽、退出的交互功能。如我們在Android手機上常常用到的物理/虛擬返回按鍵、桌面(Home)鍵、歷史記錄(Recent)鍵、ActionBar 返回鍵等等。
Jetpack庫中的Navigation組件由以下三個關鍵部分組成:
-
導航圖:一種XML資源,包含所有與導航有關的資訊,如Fragment配置、跳轉行為/方向、動畫等等;
-
NavHost:一個空容器,用於顯示導航圖中的目的地,項目中需要包含一個實現NavHost介面的默認NavHostFragment容器;
-
NavController:在NavHost容器內管理應用程式的導航行為。當用戶在應用程式中切換介面時,NavController協調容器中的目標內容交換。
優點
使用導航組件有很多好處:
-
能夠處理Fragment切換
-
能夠正確處理向上、返回的默認行為
-
提供動畫和過渡的標準化資源
-
提供深層鏈接功能
-
包含導航UI模式,例如抽屜導航和底部導航,開發者無需進行額外的處理
-
保護導航之間數據傳遞的類型安全
-
提供ViewModel支援,多Fragment間可共享ViewModel數據
-
提供AndroidStudio圖形化查看/編輯導航功能(>= 3.3版本)
簡單使用
下面是一個使用導航組件進行開發的Demo運行效果:
從實現效果上來看,整個應用程式共有8個介面,分別是主介面、註冊介面、排行介面、用戶匹配、遊戲介面、失敗介面、成功介面、用戶介面。
主要涉及的邏輯有:
-
打開應用進入主介面
-
主介面提供兩個功能,一個開始註冊;另一個進入排行介面
-
註冊介面提供開始匹配功能
-
用戶匹配提供開始遊戲功能
-
遊戲介面操作後會進入成功或失敗介面
-
遊戲成功介面可進入排行介面或匹配介面繼續遊戲
-
遊戲失敗介面可返回到匹配介面重試
-
排行介面可進入用戶介面查看資訊
好了,整個應用介面之間涉及的主要邏輯都已經理清楚了,開始導入Jetpack導航組件。
環境配置
-
使用AS 3.3及以上版本
-
添加依賴項支援
implementation deps.navigation.fragment_ktx implementation deps.navigation.runtime_ktx //implementation "androidx.navigation:navigation-fragment-ktx:2.1.0" //implementation "androidx.navigation:navigation-ui-ktx:2.1.0"
導航圖
導航圖的創建是整個應用的核心所在,它描述了所有行為的觸發順序。通過AS Design功能可看到整個應用的介面並且覆蓋所有介面可能執行的順序。
使用AndroidStudio創建導航圖時,選擇Resource type為navigation,默認會創建res/navigation目錄,並將資源文件放置於此目錄下。
以title_screen主介面配置為例,來看一下xml的構成:
<navigation ... //指定了啟動當前導航時顯示的介面 app:startDestination="@+id/title_screen"> <fragment android:id="@+id/title_screen" android:name="com.example.android.navigationsample.TitleScreen" android:label="fragment_title_screen" tools:layout="@layout/fragment_title_screen"> //每一個action都代表了介面上提供跳轉到其他介面的行為 <action android:id="@+id/action_title_screen_to_register" app:destination="@id/register" app:popEnterAnim="@anim/slide_in_left" app:popExitAnim="@anim/slide_out_right" app:enterAnim="@anim/slide_in_right" app:exitAnim="@anim/slide_out_left"/> //設置了動畫和過渡效果 <action android:id="@+id/action_title_screen_to_leaderboard" app:destination="@id/leaderboard" app:popEnterAnim="@anim/slide_in_left" app:popExitAnim="@anim/slide_out_right" app:enterAnim="@anim/slide_in_right" app:exitAnim="@anim/slide_out_left"/> </fragment> .../>
在導航圖配置時,有四個需要注意的屬性:
-
popUpTo
-
popUpToInclusive
-
launchSingleTop
-
deepLink
//launchSingleTop代表啟動當前fragment後,會棧頂復用 <action android:id="@+id/action_register_to_match" app:destination="@id/match" app:enterAnim="@anim/slide_in_right" app:exitAnim="@anim/slide_out_left" app:launchSingleTop="true" app:popEnterAnim="@anim/slide_in_left" app:popExitAnim="@anim/slide_out_right" />
//deepLink及深度鏈接,應用可通過Uri方式啟動當前Fragment: //holder.item.findNavController().navigate(Uri.parse("https://www.example.com/user/Flo")) //此種方法為靜態配置,動態配置方法請參考官方說明文檔 <fragment android:id="@+id/user_profile" android:name="com.example.android.navigationsample.UserProfile" android:label="fragment_user_profile" tools:layout="@layout/fragment_user_profile"> <argument android:name="userName" android:defaultValue="name"/> <deepLink app:uri="www.example.com/user/{userName}" /> </fragment>
<action android:id="@+id/action_in_game_to_resultsWinner" app:destination="@id/results_winner" app:popUpTo="@+id/match" app:popUpToInclusive="false" app:popEnterAnim="@anim/slide_in_left" app:popExitAnim="@anim/slide_out_right" app:enterAnim="@anim/fade_in" app:exitAnim="@anim/fade_out"/> //popUpTo屬性表示堆棧返回到某個介面,其後的棧數據清空 //popUpToInclusive屬性為true表示回到指定介面時,介面棧中是否還包括當前介面 //(如果棧中已經包含了指定要跳轉的介面,那麼只會保留一個,不指定則棧中會出現兩個 //介面相同的Fragment數據)
AndroidManifest與布局文件配置
如果要使用導航組件的深度鏈接功能,則需要在AndroidManifest中聲明導航圖,以便深度鏈接功能正常使用。
<activity... <nav-graph android:value="@navigation/navigation" /> ... </activity>
導航功能的使用需要在NavHostFragment容器中實現,因此需要指定布局顯示時使用的容器,設置默認NavHost,設置導航圖。
<layout>... <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:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" app:navGraph="@navigation/navigation"/> .../>
程式碼實現
整個Demo使用單Activity,多Fragment架構,MainActivity啟動時,載入NavHostFragment容器,解析navigation容器圖,通過startDestination屬性找到首介面進行顯示(本例首介面為TitleScreen)。
如下為TitleScreen的程式碼實現:
class TitleScreen : Fragment() { override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { val view = inflater.inflate(R.layout.fragment_title_screen, container, false) view.findViewById<Button>(R.id.play_btn).setOnClickListener { Navigation.findNavController(view).navigate(R.id.action_title_screen_to_register) }... return view } }
到此,使用導航組件進行應用程式開發的基本流程已經結束,當然導航組件提供的功能遠不止如此,它還有如頁面間數據類型的安全保護,手勢導航,導航嵌套、條件導航,自定義動畫過渡效果,使用NavigationUI更新介面等高級使用方法。具體使用可參考Google官方文檔說明。
更多科技資訊,新技術學習

