目录
一、返回按键
1.物理返回按键
如果通过app:defaultNavHost="true"
或者FragmentManager.setPrimaryNavigationFragment()
让Navigation组件监听物理返回按键事件,那么物理返回按键事件的传递如下:
ComponentActivity.onBackPressed() -> OnBackPressedDispatcher.onBackPressed() -> OnBackPressedCallback.handleOnBackPressed() -> NavController.popBackStack()
关键源码:
ComponentActivity:
public void onBackPressed() {
mOnBackPressedDispatcher.onBackPressed();
}
OnBackPressedDispatcher:
public void onBackPressed() {
Iterator<OnBackPressedCallback> iterator = mOnBackPressedCallbacks.descendingIterator();
// 通过降序寻找 最新的且enable的OnBackPressedCallback 去处理物理返回按键事件
while (iterator.hasNext()) {
OnBackPressedCallback callback = iterator.next();
if (callback.isEnabled()) {
callback.handleOnBackPressed();
return;
}
}
// 如果没有OnBackPressedCallback处理本次物理返回按键事件,则默认调用Activity的onBackPressed()方法(Activity.finish())
if (mFallbackOnBackPressed != null) {
mFallbackOnBackPressed.run();
}
}
NavController:
// 实现onBackPressedCallback
private val onBackPressedCallback: OnBackPressedCallback =
object : OnBackPressedCallback(false) {
override fun handleOnBackPressed() {
// 将栈顶的目的地弹出
popBackStack()
}
}
private fun updateOnBackPressedCallbackEnabled() {
// 1.enableOnBackPressedCallback由NavHostFragment是否为PrimaryNavigationFragment决定
// 2.destinationCountOnBackStack > 1 表示NavController返回栈中的目的地大于1
// 满足上述两个条件,NavController才会处理物理返回按键事件
onBackPressedCallback.isEnabled = (enableOnBackPressedCallback && destinationCountOnBackStack > 1)
}
由上面的内容可以推出
- 嵌套NavHost内只有一个目的地时,物理返回按键事件会由其父NavHost处理,弹出NavHost所在Fragment
- 通过ComponentActivity.getOnBackPressedDispatcher().addCallback()可以拦截Navigation组件对物理返回按键事件的处理
- 从其他应用通过隐式DeepLink导航到本应用的某个目的地,按物理返回按键会finish activity并回到其他应用的任务栈
2.Toolbar导航按钮
通过NavigationUI
绑定Toolbar后,Toolbar的导航按钮事件会由Navigation组件处理。
关键源码:
NavigationUI:
public fun setupWithNavController(toolbar: Toolbar,navController: NavController,
configuration: AppBarConfiguration =
AppBarConfiguration.Builder(navController.graph).build()
) {
// 变换目的地时变换Toolbar内容
navController.addOnDestinationChangedListener(
ToolbarOnDestinationChangedListener(toolbar, configuration)
)
// 给Toolbar设置导航按钮事件
toolbar.setNavigationOnClickListener {
navigateUp(navController, configuration) }
}
public fun navigateUp(navController: NavController, configuration: AppBarConfiguration): Boolean {
val openableLayout = configuration.openableLayout
val currentDestination = navContr