Navigation 组件旨在用于具有一个主 Activity 和多个 Fragment 目的地的应用。主 Activity 与导航图相关联,且包含一个负责根据需要交换目的地的 NavHostFragment。在具有多个 Activity 目的地的应用中,每个 Activity 均拥有其自己的导航图,记录一些Navigation下的NavOptions的使用记录
<fragment
android:id="@+id/fragmentNavRoot"
android:name="com.mitac.app2020.sep.nav.FragmentNavRoot"
android:label="FragmentNavRoot"
tools:layout="@layout/fragment_nav_root">
<action
android:id="@+id/action_navRoot_to_navPreference"
app:destination="@id/fragmentNavPreference" />
<action
android:id="@+id/action_fragmentNavRoot_to_fragmentCategory"
app:destination="@id/fragmentCategory" />
</fragment>
id :就是这action的id,之后跳转用到的
destination:就是这个action要跳到的fragment的id
1.代码里如何跳转fragment?
都是通过NavController来控制的,下边是获取Controller的方法:
![](https://img.haomeiwen.com/i3085905/8b7bdaf6dcd6b25d.png)
1.返回某个Fragment并且传递数据
返回到栈里的某个Fragment,会将在这需要跳转的Fragment的栈前的Fragment全部清出。
Bundle bundle = new Bundle(); bundle.putString(CommunityFragment.CITY_NAME_KEY, bean.getName());
NavOptions navOptions = new NavOptions.Builder()
.setPopUpTo(R.id.communityFragment, false)
.build();
Navigation.findNavController(getView()).navigate(R.id.communityFragment, bundle, navOptions);
2.点击返回
默认后退键就返回了,activity里已经处理过了。如果我们需要点击按钮返回,那么也简单:
findNavController().navigateUp()
3.返回到指定的Fragment
系统提供了两个api供我们调用:
findNavController().popBackStack()
findNavController().popBackStack(@IdRes int destinationId, boolean inclusive)
两个参数中,第一个@IdRes int destinationId
就是要到达的目标fragment的id,
也就是在navigation.xml文件中Fragment的id
比如:findNavController().popBackStack(R.id.homeFragment,false)
第二个参数boolean inclusive是个布尔值,是否需要目标fragment弹出栈
如果Fragment A 跳到B ,B再跳到C,然后C想直接回到A咋办?
如下,第一个参数就是A的fragment id,第二个参数是为是否A也弹出,这里肯定false了,我们要跳到A的,
如果第一个参数写B的id,那么第二个参数写成true倒是刚好.
findNavController().popBackStack(R.id.fragmentA,false)
4.跳转监听
我们导航来回跳转fragment的时候,可能用的是同一个toolbar或者bottomBar之类的,这时候切换fragment的时候我们可能需要修改标题或者borromBar,这时可以在activity里添加一个监听即可,监听里可以拿到要跳转的目的地信息以及参数.
findNavController(R.id.fragment).addOnDestinationChangedListener(this)
findNavController(R.id.fragment).removeOnDestinationChangedListener(this)
override fun onDestinationChanged(
controller: NavController,
destination: NavDestination,
arguments: Bundle?
) {
println("changed=======$destination=======${arguments?.size()}")
changeTitle(destination.label?:"...")
}
5.跳转支持的argument传值的参数类型
![](https://img.haomeiwen.com/i3085905/f07894abc855e98e.png)
tips:
argType 后边是类的完整名字,带路径的
如果默认值是null的话,必须添加app:nullable="true"
<action
android:id="@+id/action_fragmentNavRoot_to_fragmentSearchResult"
app:destination="@id/fragmentSearchResult"
app:popUpToInclusive="false">
<argument
android:name="data1"
android:defaultValue="@null"
app:argType="com.xxx.app2020.sep.nav.ArgSerializableTest"
app:nullable="true" />
<argument
android:name="data2"
android:defaultValue="SUN"
app:argType="com.xxx.app2020.sep.nav.ArgEnumTest" />
</action>
<fragment
android:id="@+id/fragmentSearchResult"
android:name="com.mitac.app2020.sep.nav.FragmentSearchResult"
android:label="FragmentSearchResult"
tools:layout="@layout/fragment_search_result">
<argument
android:name="data1"
android:defaultValue="@null"
app:nullable="true"
app:argType="com.nav.ArgSerializableTest" />
<argument
android:name="data2"
android:defaultValue="TODAY"
app:argType="com.nav.ArgEnumTest" />
</fragment>
//发送端:
val bundle = bundleOf("amount" to amount)
view.findNavController().navigate(R.id.confirmationAction, bundle)
//在接收目的地的代码中,请使用 getArguments() 方法来检索 `Bundle` 并使用其内容:
val tv = view.findViewById<TextView>(R.id.textViewAmount)
tv.text = arguments?.getString("amount")
6.混淆注意事项
您需要防止在缩减过程中混淆 Parcelable
、Serializable
和 Enum
类名称。您可以通过以下两种方式来实现此目的:
使用 @Keep 注解
以下示例说明了如何在代码类定义中添加 @Keep
:
@Keep class ParcelableArg : Parcelable { ... }
@Keep class SerializableArg : Serializable { ... }
@Keep enum class EnumArg { ... }
也可以在keepnames 规则中配置
您也可以将 keepnames 规则添加到您的 proguard-rules.pro 文件中,如以下示例中所示:
proguard-rules.pro
-keepnames class com.path.to.your.ParcelableArg
-keepnames class com.path.to.your.SerializableArg
-keepnames class com.path.to.your.EnumArg
7.popUpTo 和 popUpToInclusive
使用操作进行导航时,您可以选择从返回堆栈上弹出其他目的地。例如,如果您的应用具有初始登录流程,那么在用户登录后,您应将所有与登录相关的目的地从返回堆栈上弹出,这样返回按钮就不会将用户带回登录流程。
如需在从一个目的地导航到另一个目的地时弹出目的地,请在关联的 <action> 元素中添加 app:popUpTo 属性。app:popUpTo 会告知 Navigation 库在调用 navigate() 的过程中从返回堆栈上弹出一些目的地。属性值是应保留在堆栈中的最新目的地的 ID。
您还可以添加 app:popUpToInclusive="true",以表明在 app:popUpTo 中指定的目的地也应从返回堆栈中移除。
导航到目的地 | Android 开发者 | Android Developers (google.cn)
8.NavOptions配置
NavOpstions存储导航操作的特殊选项:在这里解释一下:除了目的地跳转和参数传递,其他都是特殊选项。
8.1使用位置
我们可以在两个地方设置NavOptions属性:
NavController的navigate()方法里
导航图的<action>元素里
![](https://img.haomeiwen.com/i3085905/9625237ecccbd030.png)
8.2使用举例
1.通过NavController的navigate()方法设置NavOptions
NavController navController = NavHostFragment.findNavController(this);
NavOptions navOptions = new NavOptions.Builder()
.setLaunchSingleTop(true) // 设置singleTop属性
.setPopUpTo(R.id.aFragment, true, true) // 三个参数分别为popUpToId, popUpToInclusive, popUpToSaveState
.setRestoreState(true) // 设置restoreState属性
.build();
navController.navigate(AFragmentDirections.actionAFragmentToBFragment(), navOptions);
2.通过<action>元素设置NavOptions
<action
android:id="@+id/action_aFragment_to_bFragment"
app:destination="@id/bFragment"
app:launchSingleTop="true"
app:popUpTo="@id/aFragment"
app:popUpToInclusive="true"
app:popUpToSaveState="true"
app:restoreState="true"/>
9. 跳转Fragment带动画
NavOptions navOptions = new NavOptions.Builder()
.setEnterAnim(R.anim.from_right) //进入动画
.setExitAnim(R.anim.to_left) //退出动画
.setPopEnterAnim(R.anim.to_left) //弹出进入动画
.setPopExitAnim(R.anim.from_right) //弹出退出动画
.build();
controller.navigate(R.id.action_oneFragment_to_twoFragment, null , navOptions);
网友评论