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運行效果:

![Navigation Sample](https://img2018.cnblogs.com/blog/1820853/201910/1820853-20191007165309347-2107219407.gif)

從實現效果上來看,整個應用程式共有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功能可看到整個應用的介面並且覆蓋所有介面可能執行的順序。

![導航圖](https://img2018.cnblogs.com/blog/1820853/201910/1820853-20191007165309666-956033246.webp) navigation demo導航圖

使用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官方文檔說明。

源碼在此

– END –


更多科技資訊,新技術學習
![易飛澈資訊科技](https://img2018.cnblogs.com/blog/1820853/201910/1820853-20191007165309918-238831452.webp)

歡迎關注公眾號,留言討論更多技術問題


file