如何使用 Jetpack Navigation 创建 dynamic/conditional 导航?
How can I create dynamic/conditional navigation with Jetpack Navigation?
我在尝试使用 Jetpack Navigation 库完成动态或条件导航时遇到了一个有趣的问题。
我的目标是能够继续使用 nav_graph.xml
来管理整体导航图,但同时允许基于某些因素的条件导航。
我在下面包含了一些代码,这些代码显示了我的解决方案的发展方向。问题在于它本质上需要大量维护才能使未来的条件逻辑正常工作。
我真的希望示例中的 navigateToDashboard
函数能够在没有参数或很少更改的参数的情况下执行。例如,不是传递 NavDirections
,而是传递一些标识符,让 navigateToDashboard
函数知道哪个 NavDirections
到 return。
class 管理条件逻辑的代码。
class DynamicNavImpl(private val featureFlagService: FeatureFlagService) : DynamicNav {
override fun navigateToDashboard(navDirectionsMap: Map<Int, NavDirections>): NavDirections {
val destinationIdRes = if (featureFlagService.isDashboardV2Enabled()) {
R.id.dashboardV2Fragment
} else {
R.id.dashboardFragment
}
return navDirectionsMap[destinationIdRes] ?: handleNavDirectionsException(destinationIdRes)
}
private fun handleNavDirectionsException(destinationIdRes: Int): Nothing {
throw IllegalStateException("Destination $destinationIdRes does not have an accompanying set of NavDirections. Are you sure you added NavDirections for it?")
}
}
调用站点示例
navigate(
dynamicNav.navigateToDashboard(
mapOf(
Pair(R.id.dashboardFragment, PhoneVerificationFragmentDirections.phoneVerificationToDashboard()),
Pair(R.id.dashboardV2Fragment, PhoneVerificationFragmentDirections.phoneVerificationToDashboardV2())
)
)
)
navigate(
dynamicNav.navigateToDashboard(
mapOf(
Pair(R.id.dashboardFragment, EmailLoginFragmentDirections.emailLoginToDashboard()),
Pair(R.id.dashboardV2Fragment, EmailLoginFragmentDirections.emailLoginToDashboardV2())
)
)
)
查看调用站点,您会发现这可能是个问题。如果我想添加一个新的潜在目的地,比方说 dashboardV3Fragment
,那么我必须前往每个呼叫站点并添加另一个 Pair
.
这几乎违背了 DynamicNavImpl
class 的目的。所以这就是我被困的地方。我希望能够封装决定去哪个目的地所涉及的各种变量,但似乎 NavDirections
是如何实现的,我无法做到。
我尝试了几种不同的方法,最后找到了一些感觉仍然不理想但适合我的用例的方法。
我完全放弃了使用中央动态导航管理器的想法。相反,我决定使用 "redirect" 或 "container" Fragment
来决定要显示的内容 Fragment
。
所以这是 DashboardRedirectFragment
中的新代码
childFragmentManager.beginTransaction().replace(
R.id.dashboard_placeholder,
if (featureFlagService.isDashboardV2Enabled()) {
DashboardV2Fragment.newInstance()
} else {
DashboardFragment.newInstance()
}
).commit()
我使用它的方式是在我的导航图中注册一个名为 dashboardRedirectFragment
的新目的地,并且图中需要访问仪表板的任何内容都使用 dashboardRedirectFragment
目的地。
这完全封装了重定向中的动态导航逻辑 Fragment
,并允许我继续按预期使用我的导航图。
我在尝试使用 Jetpack Navigation 库完成动态或条件导航时遇到了一个有趣的问题。
我的目标是能够继续使用 nav_graph.xml
来管理整体导航图,但同时允许基于某些因素的条件导航。
我在下面包含了一些代码,这些代码显示了我的解决方案的发展方向。问题在于它本质上需要大量维护才能使未来的条件逻辑正常工作。
我真的希望示例中的 navigateToDashboard
函数能够在没有参数或很少更改的参数的情况下执行。例如,不是传递 NavDirections
,而是传递一些标识符,让 navigateToDashboard
函数知道哪个 NavDirections
到 return。
class 管理条件逻辑的代码。
class DynamicNavImpl(private val featureFlagService: FeatureFlagService) : DynamicNav {
override fun navigateToDashboard(navDirectionsMap: Map<Int, NavDirections>): NavDirections {
val destinationIdRes = if (featureFlagService.isDashboardV2Enabled()) {
R.id.dashboardV2Fragment
} else {
R.id.dashboardFragment
}
return navDirectionsMap[destinationIdRes] ?: handleNavDirectionsException(destinationIdRes)
}
private fun handleNavDirectionsException(destinationIdRes: Int): Nothing {
throw IllegalStateException("Destination $destinationIdRes does not have an accompanying set of NavDirections. Are you sure you added NavDirections for it?")
}
}
调用站点示例
navigate(
dynamicNav.navigateToDashboard(
mapOf(
Pair(R.id.dashboardFragment, PhoneVerificationFragmentDirections.phoneVerificationToDashboard()),
Pair(R.id.dashboardV2Fragment, PhoneVerificationFragmentDirections.phoneVerificationToDashboardV2())
)
)
)
navigate(
dynamicNav.navigateToDashboard(
mapOf(
Pair(R.id.dashboardFragment, EmailLoginFragmentDirections.emailLoginToDashboard()),
Pair(R.id.dashboardV2Fragment, EmailLoginFragmentDirections.emailLoginToDashboardV2())
)
)
)
查看调用站点,您会发现这可能是个问题。如果我想添加一个新的潜在目的地,比方说 dashboardV3Fragment
,那么我必须前往每个呼叫站点并添加另一个 Pair
.
这几乎违背了 DynamicNavImpl
class 的目的。所以这就是我被困的地方。我希望能够封装决定去哪个目的地所涉及的各种变量,但似乎 NavDirections
是如何实现的,我无法做到。
我尝试了几种不同的方法,最后找到了一些感觉仍然不理想但适合我的用例的方法。
我完全放弃了使用中央动态导航管理器的想法。相反,我决定使用 "redirect" 或 "container" Fragment
来决定要显示的内容 Fragment
。
所以这是 DashboardRedirectFragment
childFragmentManager.beginTransaction().replace(
R.id.dashboard_placeholder,
if (featureFlagService.isDashboardV2Enabled()) {
DashboardV2Fragment.newInstance()
} else {
DashboardFragment.newInstance()
}
).commit()
我使用它的方式是在我的导航图中注册一个名为 dashboardRedirectFragment
的新目的地,并且图中需要访问仪表板的任何内容都使用 dashboardRedirectFragment
目的地。
这完全封装了重定向中的动态导航逻辑 Fragment
,并允许我继续按预期使用我的导航图。