Android Jetpack架構組件之Navigation

一、前言

最近簡單看了下google推出的框架Jetpack,感受此框架的內容能夠對平時的開發有很大的幫助,也能夠解決不少開發中的問題,對代碼的邏輯和UI界面實現深層解耦,打造數據驅動型UI界面。android

Android Architecture組件是Android Jetpack的一部分,它們是一組庫,旨在幫助開發者設計健壯、可測試和可維護的應用程序,包含一下組件:git

上述時Android Architecture所提供的架構組件,本文一塊兒來看一下Navigation組件的使用。github

二、Navigation簡介

導航架構組件簡化了Android應用程序中導航的實現,經過在xml中添加元素並指定導航的起始和目的地,從而在Fragment之間創建鏈接在Activity中調用xml中設置的導航action從而跳轉界面到目的地,簡單來講它和以前在活動中調用startActivity的區別就相似於代碼佈局和xml中layout佈局同樣,既簡單又可視化,以下圖就是一個navigaton的xml圖:編程

Navigation多數做用於Fragment中,不過導航組件還支持:Fragment、Activity、導航圖和子圖、自定義目標bash

三、Navigation設置操做

3.一、在項目中設置Navigation架構

  • 開啓Navigation支持
  1. 點擊 File -》 Setting -》Experimental -> 選中 Enable Navigation Editor -> Restart Studio
  • 添加項目組件依賴
dependencies {
def nav_version = "1.0.0-alpha06"

implementation "android.arch.navigation:navigation-fragment:$nav_version"
implementation "android.arch.navigation:navigation-ui:$nav_version"
androidTestImplementation "android.arch.navigation:navigation-testing:$nav_version"
}複製代碼
  • 建立 xml 文件

3.二、Navigation編輯器app

  • Navigation編輯器界面

  • Navigation編輯器的三個部分:
  1. 「目標」列表 - 列出「曲線圖編輯器」中當前的全部目標
  2. 圖表編輯器 - 包含Navigation圖的可視化表示
  3. 屬性編輯器 - 包含與Navigation圖中的目標和操做關聯的屬性

3.三、肯定目的地框架

  • 要肯定應用的目標,請使用如下步驟
  1. 從圖形編輯器,單擊新目的地 。出現「 新目標」對話框
  2. 單擊「 建立空白目標」或單擊片斷或活動。將出現「新建Android組件」對話框
  3. 在「 片斷名稱」字段中輸入名稱。此名稱是片斷類的名稱
  4. 在「 片斷佈局名稱」字段中輸入名稱。此名稱是片斷的佈局文件的名稱,單擊完成
  • Attributes面板中顯示如下屬性
  1. Type:字段包含「Fragment」或「Activity」,以指示目標是否在源代碼中實現爲片斷或活動
  2. Label:字段包含目標的XML佈局文件的名稱
  3. ID:字段包含將用於在代碼中引用目標的目標ID
  4. Class:字段包含目標類的名稱

上面的屬性選中後都會自動生成xml中的代碼,如:編輯器

<fragment android:id="@+id/blankFragment" 
           android:name="com.example.administrator.navigation.BlankFragment"
           android:label="fragment_blank" 
           tools:layout="@layout/fragment_blank">
</fragment>複製代碼

3.四、鏈接目的地ide

  • 鏈接
  1. 在圖表編輯器中,將鼠標懸停在您但願用戶導航的目標的右側。目的地上會出現一個圓圈
  2. 單擊並按住,將光標拖動到但願用戶導航到的目標上,而後釋放。繪製一條線以指示兩個目的地之間的導航
  3. 此時Fragment會添加<action>標籤

<action
    android:id="@+id/action_otherFragment_to_blankFragment"  // 在導航時調用此ID設置目的
    app:destination="@id/blankFragment" />複製代碼
  • 單機箭頭顯示操做屬性
  1. Type:操做類型
  2. ID:系統爲操做分配的ID
  3. Destination:目標片斷的id

  • 切換起始目的地
  1. 界面加載的第一個目標名稱旁邊放置一個房屋圖標
  2. 點擊對應的Fragment在右邊屬性中(或右擊)點擊「Set Start Destination「

四、實現導航

4.一、修改活動導航

  1. 活動經過實現NavHost 添加到活動佈局的界面來託管應用程序的導航, NavHost是一個空視圖,當用戶瀏覽您的應用程序時,目的地會被換入和換出,默認 NavHost實現是 NavHostFragment
  2. 將導航圖與NavHostFragment 使用navGraph屬性相關聯
  • xml中設置導航
  1. 在xml中設置navGraph的資源文件
  2. app:defaultNavHost="true」屬性,可確保您NavHostFragment攔截系統「後退」按鈕
  3. 覆蓋AppCompatActivity.onSupportNavigateUp() 並調用NavController.navigateUp
//在Activity的xml中添加fragment
<fragment
        android:id="@+id/nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        app:navGraph="@navigation/nav_graph"
        app:defaultNavHost="true"
        />
// 在Activity中設置Navcontroller
override fun onSupportNavigateUp()
        = findNavController(nav_host_fragment).navigateUp()複製代碼
  • 代碼建立 NavHostFragment實現導航
  1. 使用NavHostFragment.create() 以編程方式建立NavHostFragment
val finalHost = NavHostFragment.create(R.navigation.example_graph)

supportFragmentManager.beginTransaction()
    .replace(R.id.nav_host_fragment, finalHost)
    .setPrimaryNavigationFragment(finalHost) 
    .commit()複製代碼

4.二、將目標綁定到UI小部件

使用NavController該類導航到目的地,系統提供如下獲取NavController的方法:

  1. NavHostFragment.findNavController(Fragment)
  2. Navigation.findNavController(Activity, @IdRes int viewId)
  3. Navigation.findNavController(View)

檢索 NavController,使用其 navigate() 方法傳入navigation.xml中設置的導航action,執行導航到目標

btnFragment.setOnClickListener {
    Navigation.findNavController(btnFragment).navigate(R.id.action_blankFragment_to_secondFragment)
}複製代碼

除了上面的navigation()方法外,還能夠調用NavController.navigateUp() 和 NavController.popBackStack() 方法「向上」或「返回」,或使用 Navigation類的 createNavigateOnClickListener() 便捷方法導航到目標

button.setOnClickListener(Navigation.createNavigateOnClickListener(R.id.next_fragment, null))複製代碼

執行上面的導航,點擊按鈕跳轉到第二個Fragment

  • 將目標驅動綁定到菜單的UI組件
  1. 經過將目標id與XML中導航抽屜或溢出菜單項的id相同,將目標綁定到導航抽屜和溢出菜單
// 導航抽屜菜單xml文件
<item android:id="@id/secondFragment"
      android:title="Second"
      android:icon="@drawable/ic_launcher_foreground"
      android:menuCategory="secondary"
      app:showAsAction="always"
      />複製代碼
  1. 使用NavigationUI 類的方法,能夠將菜單中的項目鏈接到NavigationView
val navigationView = findViewById<NavigationView>(R.id.nav_view)
NavigationUI.setupWithNavController(navigationView, findNavController(mainBlankFragment))複製代碼

運行結果:

  • 設置ToolBar
// Set up ActionBar
setSupportActionBar(binding.toolbar)
NavigationUI.setupActionBarWithNavController(this, navController, drawerLayout)複製代碼

五、導航的其餘操做

5.一、在目的地之間傳遞數據

  • Bundle 方法
  1. 在圖表編輯器中,單擊接收參數的目標位
  2. 單擊「屬性」面板的「參數」部分中的「 Add(+)」
  3. 雙擊名稱並輸入參數的名稱
  4. 按Tab並輸入參數的默認值
  5. 單擊此目標以前的操做。參數默認值應包含新添加的參數
  6. 單擊「 文本」選項卡以切換到XML視圖

此時的xml中添加了參數

<argument
    android:name="value"
    app:type="integer"
    android:defaultValue="0" /複製代碼

代碼中,使用navigate() 方法建立一個Bundle並將其傳遞到目標

val bundle = Bundle()
bundle.putString("name","Blank")
bundle.putInt("number",10)
Navigation.findNavController(btnFragment).navigate(R.id.action_blankFragment_to_secondFragment,bundle)

// 在接收的代碼中,使用該 getArguments()方法檢索包並使用其內容
val tv = view.findViewById(R.id.textViewAmount)
text.text = "Name = ${arguments?.getString("name")} Number = ${arguments?.getInt("number")}"複製代碼

5.二、將目標分組爲嵌套導航圖

  1. 能夠將一系列目的地分組爲導航圖中的子圖。子圖稱爲「 嵌套圖 」,而包含圖稱爲「 根圖「
  • 要將目標分組到嵌套圖中
  1. 在「曲線圖編輯器」中,按住shift並單擊要包含在嵌套圖形中的目標
  2. 打開上下文菜單,而後選擇「 移動到嵌套圖形」 >「 新建圖形」。目標包含在嵌套圖中
  3. 雙擊嵌套圖。將顯示嵌套圖中的目標,在「目標」列表中,單擊「 根」以返回到根導航圖
<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/navigation"
            app:startDestination="@id/blankFragment">
    <fragment  ....../>
    <navigation android:id="@+id/navigation2" app:startDestination="@id/blankFragment">
        <fragment android:id="@+id/blankFragment" android:name="com.example.administrator.navigation.BlankFragment"
            ......
        </fragment>
    </navigation>
</navigation>複製代碼

此時預覽圖發生如下變化:

  • include
  1. 可使用引用其餘圖形<include>
  2. 雖然這在功能上與使用嵌套圖形相同,但<include>容許您使用其餘項目模塊或庫項目中的圖形

下面咱們將上面的兩個navigation並使用include引用,拆分以下:

  1. navigation.xml:將兩個Fragment的跳轉放在navigation中
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
          ......>
    <fragment android:id="@+id/blankFragment" android:name="com.example.administrator.navigation.BlankFragment"
              android:label="fragment_blank" tools:layout="@layout/fragment_blank">
      ......
       
      <action android:id="@+id/action_blankFragment_to_include" app:destination="@id/secondActivity"/>    // 跳轉到SecondActivity
     //<action android:id="@+id/action_blankFragment_to_include" app:destination="@id/include"/>  // 跳轉到include
     **:注意這裏不管設置哪一個,只要是跳轉到include中,就會首先到app:startDestination的界面中
    </fragment>
<include  app:graph="@navigation/include"/>
</navigation>複製代碼
  1. include.xml:將對SecondActivity的跳轉放在include中
<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/include" app:startDestination="@id/secondActivity"> // 將include的startDestination設置爲SecondActivity因此直接跳到SecondActivity    // 必須設置不然會報異常 no start destination defined via app:startDestination  
        <activity android:id="@+id/secondActivity" android:name="com.example.administrator.navigation.SecondActivity"
                  android:label="activity_second" tools:layout="@layout/activity_second"/>

</navigation>複製代碼

5.三、目標建立深層連接

  • 爲目標分配深層連接:點擊右邊屬性框中的Deep Links 填寫Url
<deepLink app:uri="https://cashdog.com/sendmoney"/>複製代碼
  • 接添加intent過濾器
  1. 對於Android Studio 3.1以前,必須手動添加intent-filter 元素
  2. 對於Android Studio 3.2+,像Activity元素中添加nav-graph元素
<activity name=".MainActivity">
<nav-graph android:value="@navigation/main_nav" />
</activity>複製代碼

5.四、目的地之間建立過渡

  1. 點擊導航的鏈接線,在右側屬性菜單的Transition中修改過分動畫
  2. 修改後的動畫會自動添加到Navigation的代碼中

此時xml中會自動補充代碼:

app:enterAnim="@anim/nav_default_enter_anim"
app:exitAnim="@anim/nav_default_exit_anim"
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
app:popExitAnim="@anim/nav_default_pop_exit_anim"複製代碼

5.五、條件導航

  • 實施條件導航

  1. 調用popBackStack()導航回原始目的地(如Login後返回Profile
  • 共同目的地
  1. 程序中多個元素訪問公共的目標
  2. 在「曲線圖編輯器」中,單擊目標以突出顯示目標
  3. 右鍵單擊目標以顯示上下文菜單
  4. 選擇添加操做>全局

此時代碼自動填充:

// 在最外層自動添加
<action android:id="@+id/action_global_secondFragment2" app:destination="@id/secondFragment"/>複製代碼

使用共同目標

viewTransactionsButton.setOnClickListener(new View.OnClickListener() {
   @Override
   public void onClick(View view) {
       Navigation.findNavController(view).navigate(R.id.action_global_mainFragment);
   }
});複製代碼

六、實戰

使用Navigation,在Activity實現各自Fragment的導航以及兩個Activity間的導航

  • 建立SecondActivity的導航文件 second.xml:引入了兩個Fragment之間的切換
<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/second" app:startDestination="@id/fragmentT">

    <fragment android:id="@+id/fragmentT" android:name="com.example.administrator.navigation.FragmentT"
              android:label="fragment_fragment_t" tools:layout="@layout/fragment_fragment_t">
        <action android:id="@+id/action_fragmentT_to_fragmentOther" app:destination="@id/fragmentOther"/>
    </fragment>

    <fragment android:id="@+id/fragmentOther" android:name="com.example.administrator.navigation.FragmentOther"
              android:label="fragment_fragment_other" tools:layout="@layout/fragment_fragment_other"/>
</navigation>複製代碼
  • 在navigation文件中添加跳轉到second.xml的Action
<action android:id="@+id/action_blankFragment_to_secondActivity2" app:destination="@id/second"/>  
// 跳轉到second導航複製代碼
  • 在MainActivity的Fragment中調用Action,跳轉到SecondActivity
btnActivity.setOnClickListener {
    val option = ActivityOptionsCompat.makeSceneTransitionAnimation(activity as Activity, imageView, "image")
    val exeras = ActivityNavigator.Extras(option)
    Navigation.findNavController(btnFragment)
        .navigate(R.id.action_blankFragment_to_secondActivity2, null, null, exeras)複製代碼

到此Navigation的使用介紹就結束了,Navigation的使用確實使應用導航的設計變得更加簡單,還有個更大的好處就是閱讀性極好,在以往咱們查看項目時,要想獲得導航須要在代碼中就行查看,如今直接能夠查看xml文件便可,是否是很方便,好了Android Jetpack組件快要介紹完了,敬請期待

本文Navigation的Demo,歡迎Star

相關文章
相關標籤/搜索