拦截 NavigationUI.onNavDestinationSelected() 以使用 "inclusive = true" 使 backstack 弹出

Intercept NavigationUI.onNavDestinationSelected() to make backstack pop with "inclusive = true"

我已经通过 navigation_view.setupWithNavController(navController) 连接了我的菜单 xml 和 Android 导航组件,并且一切正常。我的菜单的一部分是注销选项。如果用户选择此导航目的地,应用程序应导航到 AuthorizationFragment 并将返回堆栈弹出到此 Fragment 并将 inclusive 设置为 true 以删除所有先前的片段。

我查看了导航库的代码,发现应该发生这种情况:

NavigationUI.onNavDestinationSelected():

/**
 * Attempt to navigate to the {@link NavDestination} associated with the given MenuItem. This
 * MenuItem should have been added via one of the helper methods in this class.
 *
 * <p>Importantly, it assumes the {@link MenuItem#getItemId() menu item id} matches a valid
 * {@link NavDestination#getAction(int) action id} or
 * {@link NavDestination#getId() destination id} to be navigated to.</p>
 * <p>
 * By default, the back stack will be popped back to the navigation graph's start destination.
 * Menu items that have <code>android:menuCategory="secondary"</code> will not pop the back
 * stack.
 *
 * @param item The selected MenuItem.
 * @param navController The NavController that hosts the destination.
 * @return True if the {@link NavController} was able to navigate to the destination
 * associated with the given MenuItem.
 */
public static boolean onNavDestinationSelected(@NonNull MenuItem item,
        @NonNull NavController navController) {
    NavOptions.Builder builder = new NavOptions.Builder()
            .setLaunchSingleTop(true)
            .setEnterAnim(R.anim.nav_default_enter_anim)
            .setExitAnim(R.anim.nav_default_exit_anim)
            .setPopEnterAnim(R.anim.nav_default_pop_enter_anim)
            .setPopExitAnim(R.anim.nav_default_pop_exit_anim);
    if ((item.getOrder() & Menu.CATEGORY_SECONDARY) == 0) {
        builder.setPopUpTo(findStartDestination(navController.getGraph()).getId(), false);
    }
    NavOptions options = builder.build();
    try {
        //TODO provide proper API instead of using Exceptions as Control-Flow.
        navController.navigate(item.getItemId(), null, options);
        return true;
    } catch (IllegalArgumentException e) {
        return false;
    }
}

所以我的问题是,是否有一种方法可以重写此方法并构建 NavOptions,这些 NavOptions 将返回堆栈弹出到包含选项设置为 true 的目标 ID?

像往常一样,睡过头有帮助。我发现您可以轻松设置自己的 NavigationItemSelectedListener。另外,我在问题中提到的方法是 public 静态的,因此它也可以很容易地称为后备功能。

这是我的代码:

navigation_view.setNavigationItemSelectedListener { item: MenuItem ->

    // check for my special case where I want to pop everything
    // from the backstack until we reach the login fragment
    if (item.itemId == R.id.fragment_auth) {
        val options = NavOptions.Builder()
            .setPopUpTo(navController.currentDestination!!.id, true)
            .setLaunchSingleTop(true)
            .build()
        navController.navigate(R.id.action_global_authFragment, null, options)
        true // return true -> we handled this navigation event

    } else {

        // Fallback for all other (normal) cases.
        val handled = NavigationUI.onNavDestinationSelected(item, navController)

        // This is usually done by the default ItemSelectedListener.
        // But there can only be one! Unfortunately.
        if (handled) drawer_layout.closeDrawer(navigation_view)

        // return the result of NavigationUI call
        handled
    }
}