github地址:
github分支:navigation_operation
Navigation堆栈操作
导航的出栈操作
本章节中的两个方法都是用来出栈导航组件的,区别是popBackStack的方式更加精细
1、findNavController().navigateUp()
这个方式对导航组件进行的出栈简单粗暴,仅仅是把当前栈顶的组件进行出栈,方法的boolean型返回值表示是否出栈成功。如果如果导航失败的话我们可以主动对组件的出栈进行逻辑上的补救
代码示例
val navigarionResult = findNavController().navigateUp() println("是否导航出栈成功:$navigarionResult") 复制代码
2、findNavController().popBackStack(R.id.AFragment,false)
这个方法用于执行返回指定页面的操作,例如本例: 进入的时候我们点击AFragment的按钮跳转到BFragment,在BFragment中执行如下代码:
val popBackStack = findNavController().popBackStack(R.id.AFragment,false) println("是否返回:$popBackStack") 复制代码
就可以指定返回AFragment。
popBackStack的第二个参数说明:
true:从B返回A的时候会把A出栈,然后重新打开A
false:从B返回A的时候A不会出栈,保留跳转到B之前的状态
popUpTo 和 popUpToInclusive
先看一下我们的导航图代码
<?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" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/navigation_popup" app:startDestination="@id/popUpFragment"> <fragment android:id="@+id/popUpFragment" android:name="com.mage.navigationdemo.pop.PopUpFragment" android:label="fragment_pop_up" tools:layout="@layout/fragment_pop_up" > <action android:id="@+id/action_popUpFragment_to_popAFragment" app:destination="@id/popAFragment" /> </fragment> <fragment android:id="@+id/popAFragment" android:name="com.mage.navigationdemo.pop.PopAFragment" android:label="fragment_pop_a" tools:layout="@layout/fragment_pop_a" > <action android:id="@+id/action_popAFragment_to_popBFragment" app:destination="@id/popBFragment" /> </fragment> <fragment android:id="@+id/popBFragment" android:name="com.mage.navigationdemo.pop.PopBFragment" android:label="fragment_pop_b" tools:layout="@layout/fragment_pop_b" > <action android:id="@+id/action_popBFragment_to_popUpFragment" app:popUpToInclusive="true" app:popUpTo="@id/popUpFragment" app:destination="@id/popUpFragment" /> </fragment> </navigation> 复制代码
这段导航图的代码实现如下效果: 从PopUpfragment跳转到PopUpAFragment再跳转到PopUpBFragment,正常情况下如果一直这么下去会无限跳转,产生无数个Fragment实例。
但是我们的代码中,在PopBFragment跳转PopUpfragment的activion中添加了popUpTo和popUpToInclusive。
其中popUpTo表示从PopBfragment回到PopUpfragment,过程中会把中间的Fragment也就是PopAFragment出栈,这样就不会同时存在多个Fragment实例了。而popUpToInclusive的作用就是在这个过程中将PopUpFragment也出栈然后重新创建。
插播一个报错
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mage.navigationdemo/com.mage.navigationdemo.PopUpToTestActivity}: java.lang.IllegalStateException: Activity com.mage.navigationdemo.PopUpToTestActivity@a289b29 does not have a NavController set on 2131230963 复制代码
出现这个错误的场景复现:
应用首页MainActivity是一个导航图组件(NavHostFragment),我们再MainActivity的Fragment中使用startActivity方式跳转到PopUpToTestActivity,在PopUpToTestActivity的onCreate方法中调用如下代码
findNavController(R.id.nav_popuptotest).navigate(R.id.popUpFragment) 复制代码
跳到导航图PopUpFragment,然后就报了上面的错误。
解决的方式如下面的代码:
val fragment:NavHostFragment = supportFragmentManager.findFragmentById(R.id.nav_popuptotest) as NavHostFragment fragment.navController.navigate(R.id.popUpFragment) 复制代码
即通过supportFragmentManager找到组件的NavHostFragment,利用NavHostFragment的NavController进行路由跳转
!!!讲一个 findNavController().popBackStack(R.id.AFragment,true)的坑
代码如下:
- 从A跳转到B
content.findViewById<Button>(R.id.btn_toBFragment).setOnClickListener { findNavController().navigate(R.id.action_AFragment_to_BFragment) } 复制代码
- 从B使用popBackStack(R.id.AFragment,true)返回A
val popBackStack = findNavController().popBackStack(R.id.AFragment,true) println("是否返回:$popBackStack") 复制代码
- 再从A使用导航组件跳转到B
content.findViewById<Button>(R.id.btn_toBFragment).setOnClickListener { findNavController().navigate(R.id.action_AFragment_to_BFragment) } 复制代码
第三部代码会报错:
java.lang.IllegalArgumentException: Navigation action/destination com.mage.navigationdemo:id/action_AFragment_to_BFragment cannot be found from the current destination NavGraph(com.mage.navigationdemo:id/navigation) startDestination={Destination(com.mage.navigationdemo:id/AFragment) label=fragment_a class=com.mage.navigationdemo.AFragment} 复制代码
报错的原因就是找不到导航图,
原因分析:我们返回AFragment的时候AFragment被重新创建,不再是根视图了,也就是说新的AFragment是不与我们的navigation导航图文件进行关联的,所以自然无法使用导航组件跳转到BFragment的。
此种情况应该会有解决方案的,目前先不向这个方向探索
Navigation动画
使用Navigation的时候我们可以向导航视图中添加动画,实现跳转动画过度效果。
添加过度动画的方式:
模板操作
我们可以再navigation面板中手动操作添加系统的动画模板
本例中代码效果
本例中创建两个Fragment,分别是AFragment和BFragment,我们再在AFragment跳转到BFragment,在这个跳转的action中间添加动画
效果: