欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android JetPack架构组件学习之Navigation

程序员文章站 2022-03-13 17:09:05
...

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,如下图所示:
    Android JetPack架构组件学习之Navigation
    这种方式会在一级路径下创建Fragment。
    Android JetPack架构组件学习之Navigation
  2. 外部创建后,在编辑器中引入
    Android JetPack架构组件学习之Navigation
    可引入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
    一种方式,在编辑器可视界面中拖线连接。
    Android JetPack架构组件学习之Navigation
    另一种方式,在xml代码界面,为fragment添加。两种方式原理相同。
    Android JetPack架构组件学习之Navigation

  • 处理跳转
    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。
    Android JetPack架构组件学习之Navigation
    如图,在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)
      }