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)
      }
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章