Android JetPack架構組件學習之Navigation

Navigation

Navigation簡介

導航架構組件簡化了Android應用程序中導航的實現,通過在xml中添加元素並指定導航的起始和目的地,從而在Fragment之間建立連接,在Activity中調用xml中設置的導航action實現跳轉界面到目的地。簡單來說,它和之前在活動中調用startActivity的區別就類似於代碼佈局和xml中layout佈局一樣,既簡單又可視化。

Navigation設置操作

在項目中設置Navigation

  • 在項目中開啓Navigation支持

  • 添加組件依賴

    def nav_version = "1.0.0-alpha06"
    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編輯器

  • 創建資源文件
    在 res 目錄右擊,選擇 New > Android Resource File,Resource type 選擇 Navigation。
  • 創建destination(目的地)
    創建destination的方式分爲兩種
  1. 在Navigation編輯器中Create blank destination,如下圖所示:
    在這裏插入圖片描述
    這種方式會在一級路徑下創建Fragment。
    在這裏插入圖片描述
  2. 外部創建後,在編輯器中引入
    在這裏插入圖片描述
    可引入Activity,Fragment等組件。
  • 配置navigation

    • android:name,指定Fragment路徑;
    • tools:layout,指定佈局文件;
    • app:startDestination,指定起始項。
    <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/nav_test"
              app:startDestination="@id/test1Fragment">
    
      <fragment android:id="@+id/test1Fragment"
      			android:name="com.sanmen.bluesky.jetpackdemo.Test1Fragment"
                android:label="fragment_test1" 
                tools:layout="@layout/fragment_test1">
      </fragment>
      ...
    </navigation>
    

在Activity中引用

  • 第一種方式是在 xml 裏寫 fragment。如下:

    <android.support.constraint.ConstraintLayout
          ...>
      ...
      <fragment
              android:layout_width="0dp"
              android:layout_height="0dp"
              android:id="@+id/fragment"
              android:name="androidx.navigation.fragment.NavHostFragment"
              app:navGraph="@navigation/nav_test"
              app:defaultNavHost="true"
              ...>
     </android.support.constraint.ConstraintLayout>
    
    • android:name,指定 NavHostFragment,它實現了 NavHost,這是一個用於放置管理 destination 的空視圖。
    • app:navGraph,關聯 NavHostFragment 和 nav_graph.xml 。
    • app:defaultNavHost,指定 NavHostFragment 可以攔截處理返回鍵。
  • 第二種方式是通過代碼創建 NavHostFragment,修改 Activity 的 xml:

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.constraint.ConstraintLayout 
      ... > 
    
      <FrameLayout
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:id="@+id/frame_layout" />
    </android.support.constraint.ConstraintLayout>
    

    然後再Activity中引入:

    override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContentView(R.layout.activity_main)
      
      val finalHost = NavHostFragment.create(R.navigation.nav_test)
      supportFragmentManager.beginTransaction()
              .replace(R.id.frame_layout, finalHost)
              .setPrimaryNavigationFragment(finalHost) // 等價於 xml 中的 app:defaultNavHost="true"
              .commit()
    }
    

Navigation連接

  • 連接destination
    一種方式,在編輯器可視界面中拖線連接。
    在這裏插入圖片描述
    另一種方式,在xml代碼界面,爲fragment添加。兩種方式原理相同。
    在這裏插入圖片描述

  • 處理跳轉
    Navigation的跳轉通過NavController對象來實現。獲取方式如下:

    • NavHostFragment.findNavController(Fragment)
    • Navigation.findNavController(Activity, @IdRes int viewId)
    • Navigation.findNavController(View)

    調用 NavController 的 navigate 方法執行跳轉,navigate 的參數可以是一個 destination(這裏就是 fragment 在導航圖 nav_graph 中的 id),也可以是 action 的 id。

     override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
          super.onViewCreated(view, savedInstanceState)
    
          btnToBlank!!.setOnClickListener {
              //跳轉方式1
              Navigation.findNavController(getView()!!)
                  .navigate(R.id.action_test1Fragment_to_blankFragment)
          }
          btnToPaging!!.setOnClickListener {
              //跳轉方式2
              NavHostFragment.findNavController(this)
                  .navigate(R.id.action_test1Fragment_to_pagingActivity)
          }
      }
    
  • 添加跳轉動畫
    點擊目標箭頭(提示頁面指向的箭頭),並在屬性面板中設置動畫Transitions。
    在這裏插入圖片描述
    如圖,在text1Fragment到blankFragment之間的跳轉添加一個enter動畫,在代碼界面會發生如下改變(指定了當前Action的app:enterAnim屬性):

    ...
    <fragment android:id="@+id/test1Fragment" android:name="com.sanmen.bluesky.jetpackdemo.Test1Fragment"
                android:label="fragment_test1" tools:layout="@layout/fragment_test1">
          <action android:id="@+id/action_test1Fragment_to_blankFragment" app:destination="@id/blankFragment"
                  app:enterAnim="@anim/nav_default_enter_anim"/>
          ...
      </fragment>
    
  • 傳遞數據

    • 要跳轉到BlankFragment,要往 BlankFragment裏帶數據,在目的 Fragment 裏添加 < argument>
      <navigation xmlns:android="http://schemas.android.com/apk/res/android"
      ... >
      
        <fragment android:id="@+id/blankFragment" android:name="com.sanmen.bluesky.jetpackdemo.BlankFragment"
                android:label="fragment_blank" tools:layout="@layout/fragment_blank">
      
          <action android:id="@+id/action_blankFragment_to_liveDataActivity" app:destination="@id/liveDataActivity"
                  app:enterAnim="@anim/nav_default_enter_anim"/>
      
          <argument android:name="value" android:defaultValue="defaultValue=1" />
        </fragment>
      </navigation>
      
    • Test1Fragment添加數據
      ...
      btnToBlank!!.setOnClickListener {
              //利用Bundle對象發送數據
              val bundle = Bundle()
              bundle.putString("name","Blank")
              bundle.putInt("year",1210)
              //跳轉方式1
              Navigation.findNavController(getView()!!)
                  .navigate(R.id.action_test1Fragment_to_blankFragment,bundle)
          }
      ...
      
    • BlankFragment 獲取數據
      override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,savedInstanceState: Bundle?): View? {
       ...
       //// 在接收的代碼中,使用該 getArguments()方法檢索包並使用其內容
       arguments?.let {bundle ->
             var name = bundle.getString("name")
             var year = bundle.getInt("year")
             tvValue!!.text = "name:$name,year:$year"
         }
       ...
      }
      

問題記錄

  • fragment中默認創建的OnFragmentInteractionListener 接口用於處理Fragment之間的通信,基於共同的Activity爲橋樑,並在Activity中實現OnFragmentInteractionListener 接口。
     interface OnFragmentInteractionListener {
          // TODO: Update argument type and name
          fun onFragmentInteraction(uri: Uri)
      }
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章