如何使用JetPack组件之一Navigation组件

如何使用Navigation的JetPack组件

设置环境

  • android studio需是3.3以及更高版本
  • 声明依赖

    dependencies {
    
    def nav_version = "2.1.0-alpha05"
    
    implementation "androidx.navigation:navigation-fragment:$nav_version" // For Kotlin use navigation-fragment-ktx
    implementation "androidx.navigation:navigation-ui:$nav_version" // For Kotlin use navigation-ui-ktx
    }
    
  • 如果使用safe args

    • 在最顶层(一般是Project的build.gradle)gradle文件里添加:

      buildscript {
          repositories {
              google()
          }
          dependencies {
              classpath "androidx.navigation:navigation-safe-args-gradle-plugin:2.1.0-alpha05"
          }
      }
      
    • 然后在app moudle的build.gradle里添加:

      apply plugin: "androidx.navigation.safeargs"
      
      • 如果只使用kotlin则

        apply plugin: "androidx.navigation.safeargs.kotlin"
        

创建导航图

  • 用户可以到app任何可以导航到的地方,这些目的地通过action进行连接
  • 导航图(navigation graph)是一个包含了action和destination的资源文件(xml),该文件包含了所有导航路径
  • 如下图所示(navigation-graph-1.png),该应用程序包含5个action和6个destination,每个destination由缩略图表示,连接操作由箭头表示,箭头显示用户如何从一个destination到达另一个 

    • 其中红色圈1目的地是应用程序中不同的内容区域。红色圈2表示action是表示用户可以使用的路径的目的地之间的逻辑连接。
  • 实操步骤

    1. 在项目窗口,res目录上单击右键,然后选择“New”→“Android Resource File”,出现android resource File对话框
    2. 在出现的对话框中输入File name,例如“navgraph”(例如navgraph.xml)
    3. Resouce Type下拉列表中选择navigation,然后点击ok

Navigation Editor

  • 红色圈1 Destination Pannel:列出导航host和当前图形编辑器中的所有目的地。
  • 红色圈2 Graph Editor图形编辑器:包含导航图的可视化表示。您可以在“design”视图和Text视图中的基础XML表示之间切换
  • 红色圈3 Attribute属性:显示导航图中当前选定项的属性。

  • 单击Text选项卡查看相应的XML,它应该类似于以下代码片段:

    <?xml version="1.0" encoding="utf-8"?>
    <navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/nav_graph">
    </navigation>
    
    • 元素<navigation>是导航图的根元素。在将目的地和连接操作添加到图形时,您可以在这里看到相应的<destination>和<action>元素作为子元素。如果您有嵌套图,它们将显示为子元素

Activity里添加NavHost

  • Navigation Host是一个空的容器,用户在您的应用程序中导航时,将在其中交换目的地。
  • navigation host必须从NavHost派生,默认NavHost实现是NavHostFragment
  • navigation component是为含有多个fragment的主Activity应用程序设计的。主活动与导航图相关联,并包含一个NavHostFragement,它负责根据需要交换目的地。在具有多个Activity目的地的应用程序中,每个Activity都有自己的导航图
  • 实操步骤

    • Add a NavHostFragment via XML

      <?xml version="1.0" encoding="utf-8"?>
      <android.support.constraint.ConstraintLayout
      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:layout_width="match_parent"
      android:layout_height="match_parent"
      tools:context=".MainActivity">
      <androidx.appcompat.widget.Toolbar
      .../>
      <fragment
      android:id="@+id/nav_host_fragment"
      android:name="androidx.navigation.fragment.NavHostFragment"
      android:layout_width="0dp"
      android:layout_height="0dp"
      app:layout_constraintLeft_toLeftOf="parent"
      app:layout_constraintRight_toRightOf="parent"
      app:layout_constraintTop_toTopOf="parent"
      app:layout_constraintBottom_toBottomOf="parent"
      app:defaultNavHost="true"
      app:navGraph="@navigation/nav_graph" />
      <com.google.android.material.bottomnavigation.BottomNavigationView
      .../>
      </android.support.constraint.ConstraintLayout>
      
      • 注意

        • android:name 属性包含了实现NavHost的类名
        • app:navGraph 属性将NavHostFragment与导航图关联起来,导航图指定了用户可以导航到的NavHostFragment中的所有目的地。
        • app:defaultNavHost="true" 属性确保NavHostFragment拦截到系统Back键。请注意,只有一个NAVhost可以是默认的。如果在同一布局中拥有多个host(例如,两个窗格布局),请确保仅指定一个默认的Navhost
      • 你可以使用LayoutEditor 天剑NavHostFragment到Activity参照以下步骤:

        • 在项目文件列表中,双击Activity的布局XML文件,在布局编辑器中(layout Editor)打开它。
        • 使用调色板面板,选择“容器”类别,或者搜索“NavHostFragment”
        • 将NavHostFragment视图拖到Activity中
        • 接下来,在出现的Navigation Graphs 对话框中,选择与此NavHostFragment相关联的相应导航图,然后单击OK

将destination添加到导航图(nav_Graph)中

您可以从现有的Fragment或Activity创建目标。还可以使用导航编辑器(Navigation Editor)创建新的目标或创建占位符,以便稍后用
Fragment或Activity替换。
  • 从现有Fragment或Activity创建目标(destination)

    • 如果您有要添加到导航图中的现有目标类型,请单击“New Destination”,然后在显示的下拉列表中单击相应的目的地。现在,您可以在“design”视图中看到目标的预览,以及导航图的Text视图中相应的XML。
  • 创建新的Fragment Destination

    • 使用导航编辑器(Navigation Editor)添加新的destination类型,执行以下操作:
      • 在Navigation Editor中,单击“New Destination” icon,然后单击“Create new Destination
      • 在出现的Configure Component对话框中,创建您的Fragment
  • 从DialogFragment创建新的Destination

    • 如果您有一个现有的DialogFragment,您可以使用<dialog>元素将DialogFragment添加到您的导航图中,如下面的示例所示:

      <?xml version="1.0" encoding="utf-8"?>
      <navigation xmlns:android="http://schemas.android.com/apk/res/android"
                  xmlns:app="http://schemas.android.com/apk/res-auto"
                  android:id="@+id/nav_graph">
      
      ...
      
      
      <dialog
          android:id="@+id/my_dialog_fragment"
          android:name="androidx.navigation.myapp.MyDialogFragment">
          <argument android:name="myarg" android:defaultValue="@null" />
              <action
                  android:id="@+id/myaction"
                  app:destination="@+id/another_destination"/>
      </dialog>
      
      ...
      
      </navigation>
      
    • Placeholder destinations

      • 您可以使用占位符来表示未实现的目的地。占位符用作目标的可视表示形式。在导航编辑器中,您可以像使用其他目标一样使用占位符。
      • 在运行应用程序之前,必须将占位符(placeHolder)的class属性更改为现有的目的地。占位符不会导致编译错误,如果尝试导航到占位符目的地,应用程序将引发运行时异常

Destination剖析

单击任意目标以将其选中,并在“属性”面板中注意以下属性:

  • type”字段指示目标是否被实现为源代码中的片段、活动或其他自定义类。
  • ID字段包含用于引用代码中的目标的目标的ID。
  • class下拉列表显示与目标关联的类的名称。您可以单击此下拉列表将关联类更改为另一目标类型。
  • label字段是layout文件名

指定一个屏幕作为start destination

开始目标是用户在打开应用程序时看到的第一个屏幕,这是用户退出应用程序时看到的最后一个屏幕。导航编辑器使用房屋图标指示起始目的地

  • 一旦您的所有目的地就位,您可以通过以下操作选择一个开始目的地:
    • In the Design tab, click on the destination to highlight it.
    • right click,然后点击Set as Start Destination

Connect destinations

action是目的地之间的逻辑连接。action在导航图中表示为箭头。action通常将一个目的地连接到另一个目的地,尽管你也可以创建全局操作,从你的应用程序中的任何地方把你带到一个特定的目的地

通过操作,您代表了用户可以通过应用程序选择的不同路径。注意,要真正导航到目的地,仍然需要编写代码来执行导航。这将在本主题后面的“导航到目的地”部分中讨论。

导航到目的地

  • 导航到目的地是使用NavController完成的,NavController是一个管理Navhost中应用程序导航的对象。每个Navhost都有相应的NavController。NavController提供了几种导航到目的地的不同方法,这些方法将在下面的部分中进一步介绍。
  • 要获得Fragment、Activity或View的NavController,请使用以下方法之一:

    Kotlin:
    
    Fragment.findNavController()
    View.findNavController()
    Activity.findNavController(viewId: Int)
    
    Java:
    
    NavHostFragment.findNavController(Fragment)
    Navigation.findNavController(Activity, @IdRes int viewId)
    Navigation.findNavController(View)
    
  • Navigate using ID

    • navigate(int)获取操作或目标的资源ID。以下代码片段显示了如何导航到ViewTransactionsFragment:

      viewTransactionsButton.setOnClickListener { view ->
          view.findNavController().navigate(R.id.viewTransactionsAction)
      }
      
    • 在使用ID导航时,我们强烈建议在可能的情况下使用action。action在导航图中提供其他信息,直观地显示您的目的地如何相互连接。通过创建action,您可以用 Safe Args-generated的操作替换资源ID,从而提供额外的编译时安全性。通过使用action,您还可以在目的地之间进行动态转换。有关更多信息,请参见在目的地之间进行动画转换

  • Navigate using URI

    • You can use navigate(Uri) to navigate directly to an implicit deep link destination, as shown in the following example:

      val navController = findNavController()
      val deeplink = Uri.parse("android-app://androidx.navigation.app/profile")
      findNavController().navigate(deeplink)
      
  • popUpTo and popUpToInclusive

    • 若要在从一个目的地导航到另一个目的地时弹出目的地,请向相关的元素添加app:popUpTo属性。app:popUpTo告诉导航库从后台堆栈中弹出一些目的地,作为导航()调用的一部分。属性值是应该保留在堆栈上的最近目标的ID

    • 您还可以包括app:popUpToInclusivd="true",以指示应用程序中指定的目标:还应该从后堆栈中删除PopupTo中指定的目标。 对于每个导航操作,都会向后台堆栈添加一个目标。如果要在此流中反复导航,则后端堆栈将包含每个目标的多个集合(A、B、C、A等)。为了避免这种重复,您可以在从目的地C到目的地A的操作中指定app:popUpTo和app:popUpToInclusive,如下面的示例所示: 

      <fragment
      android:id="@+id/c"
      android:name="com.example.myapplication.C"
      android:label="fragment_c"
      tools:layout="@layout/fragment_c">
      
      <action
          android:id="@+id/action_c_to_a"
          app:destination="@id/a"
          app:popUpTo="@+id/a"
          app:popUpToInclusive="true"/>
      </fragment>
      
      • 在到达目的地C之后,后堆栈包含每个目的地(A,B,C)的一个实例。当导航到目标A时,我们还将PopuptoA,这意味着我们在导航时从堆栈中删除了B和C。With app:popUpToInclusive="true",我们也会弹出堆栈的第一个A,从而有效地清除它。请注意,如果您不使用app:popUpToInclusive,您的后堆栈将包含两个目标A实例

posted on 2019-06-21 15:38  endian11  阅读(356)  评论(0编辑  收藏  举报

导航