Jetpack系列:應用內導航的正確使用方法


今天小編要分享的還是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運行效果:

![](https://img2018.cnblogs.com/blog/1820853/201910/1820853-20191007173520099-744530386.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-20191007173538621-586635565.png)
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 -


歡迎關注公眾號,留言討論更多技術問題
![file](https://graph.baidu.com/resource/212c1356db6cfebdb23e101569820474.png)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM