我正在尝试在完成新的导航事件时使用 Jetpack 导航库获取回调以更改状态栏颜色。
到目前为止,我发现 navController.addOnDestinationChangedListener
它会在新导航开始时通知我,但在完成时不会通知我,这意味着进入/退出转换已完成。
有什么方法可以知道所有导航转换何时完成?
你可以使用这样的东西:
val navHostFragment = supportFragmentManager.findFragmentById(R.id.nav_host_fragment)
navHostFragment?.childFragmentManager?.addOnBackStackChangedListener {
val currentFragment = navHostFragment.childFragmentManager.fragments.firstOrNull()
if (currentFragment is YourFragment) {
// your code here
}
}
你可以参考这个答案来实现它。 简而言之,作为一种解决方法,您可以在事务启动时向动画添加一些延迟。
如答案所述; 当您单击"导航到 X 片段"按钮时,片段替换开始。 所以延迟仅在片段事务动画中,而不是在替换中
通过在 res 文件夹下的 anim 文件夹your_anim_name.xml文件中添加android:startOffset="300"
来添加动画延迟。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="together">
<alpha
android:startOffset="300"
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:duration="400"
android:interpolator="@android:interpolator/accelerate_decelerate"
/>
<translate
android:startOffset="300"
android:fromYDelta="100%"
android:toYDelta="0%"
android:duration="400"
android:interpolator="@android:interpolator/accelerate_decelerate"
/>
答案很简单,就像"abc"一样:要在过渡结束后执行某些工作,请在Fragment.View
上添加侦听器
例如,如果我们只需要在当前Fragment
绘制并显示在屏幕上后跳转到另一个Destination
,只需将此钩子放在 onResume 回调中:
override fun onResume() {
super.onResume()
view?.animation?.setAnimationListener(object: Animation.AnimationListener {
override fun onAnimationRepeat(animation: Animation?) {}
override fun onAnimationStart(animation: Animation?) {}
override fun onAnimationEnd(animation: Animation?) {
// Do the navigation or whatever you want
}
})
}
我遇到了同样的问题,终于找到了解决方法。
这个想法是,当当前片段的退出动画结束时,调用该片段的onDestroyView
。
所以只要进入和退出动画的持续时间相同,我们就可以使用此方法作为回调。
class BaseFragment() {
private var leavingDestination = false
fun navigateNext() {
leavingDestination = true
findNavController().navigate(blaBlaBla)
}
fun onNavigationAnimationEnds() {
TODO()
}
// We just need to add an extra check, to be sure that onNavigationAnimationEnds is not called on configuration change
override fun onDestroyView() {
if(leavingDestination) {
onNavigationAnimationEnds()
leavingDestination = false
}
}
}
我使用所描述的方法调用后退/退出片段中的一些代码。如果您需要在导航到的片段中回调,则可以只使用共享ViewModel
。如 ActivityViewModel 或 NavGraph scoped ViewModel。
像这样:
class FragmentA() {
private val mainActivityViewModel by activityViewModels<MainActivityViewModel> { viewModelFactory }
...
override fun onDestroyView() {
if(leavingDestination) {
mainActivityViewModel.onNavigationAnimationEnds()
leavingDestination = false
}
}
}
...
class MainActivity() {
private val _navigationAnimationEndsEvent = MutableLiveData(Event())
val navigationAnimationEndsEvent: LiveData<Event>; get() = _navigationAnimationEndsEvent
fun onNavigationAnimationEnds() {
_navigationAnimationEndsEvent.value = Event()
}
}
...
class FragmentB() {
private val mainActivityViewModel by activityViewModels<MainActivityViewModel> { viewModelFactory }
override fun onActivityCreated() {
...
mainActivityViewModel.navigationAnimationEndsEvent.observe(viewLifecycleOwner, Observer {
it.getContentIfNotHandled()?.let {
onNavigationAnimationsEnds()
}
})
}
private fun onNavigationAnimationEnds() {
TODO()
}
}
我使用的事件类:
open class Event<out T>(private val content: T) {
var hasBeenHandled = false; private set
fun getContentIfNotHandled() = if (hasBeenHandled) null else {
hasBeenHandled = true
content
}
fun peekContent(): T = content
}
PS:我尝试覆盖onCreateAnimation/onCreateAnimator函数并向它们添加侦听器,但从未调用过它们。