如何使用JetPack组件之一Navigation组件 - endian11
如何使用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是表示用户可以使用的路径的目的地之间的逻辑连接。
-
实操步骤
- 在项目窗口,res目录上单击右键,然后选择“New”→“Android Resource File”,出现android resource File对话框
- 在出现的对话框中输入File name,例如“navgraph”(例如navgraph.xml)
- 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
- 使用导航编辑器(Navigation Editor)添加新的destination类型,执行以下操作:
-
从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实例
-