Skip to content Skip to sidebar Skip to footer

Android Navigation Component Pop To Transition Issue

I have 2 actions Action1

Solution 1:

I ended up overriding onCreateAnimation in the fragment that calls navigate. This exemple shows how to navigate through nested nav graphs by ID and replace the pop exit animation (or popExitAnim) conditionnally.

overridefunonCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int): Animation? {
    val navController = findNavController()
    val graph = navController.graph.findNode(R.id.onboardingGraph) as NavGraph
    val dest = graph.findNode(R.id.confirmationFragment)
    if (!enter && dest != null && navController.currentDestination?.id == dest.id) {
        return AnimationUtils.loadAnimation(requireContext(), R.anim.slide_out_left)
    }
    returnsuper.onCreateAnimation(transit, enter, nextAnim)
}

Note that this particular situation is partly due to the directional nature of slide animations.

Solution 2:

This is bit of a tough one to solve due to NavOptions being internally handled by the convenience methods used in binding your drawer to the navigation graph. I originally tested this solution with the settings menu and onOptionsItemSelected but the basic idea should work here as well.

First, make sure your menu item IDs correspond to those of your navigation fragments:

<menuxmlns:android="http://schemas.android.com/apk/res/android">

    ...

    <itemandroid:id="@+id/example_id"... /></menu>
<navigationxmlns:android="http://schemas.android.com/apk/res/android"... >

    ...

    <fragmentandroid:id="@+id/example_id"... /></navigation>

Now, rather than using the ready-made methods for connecting the drawer to your NavController Implement NavigationView.OnNavigationItemSelectedListener in your NavHost activity and override the method onNavigationItemSelected like so:

@OverridepublicbooleanonNavigationItemSelected(@NonNull MenuItem item) {
    NavHostnavHost= Navigation.findNavController(this, R.id.your_nav_host_fragment);
    return NavigationUI.onNavDestinationSelected(item, navHost);
}

This will forward the selection as a navigation in your graph. Replace your_nav_host_fragment with the fragment ID on which you set app:defaultNavHost="true".

You will notice that while this works, it still defaults to the slide animations. This is because the NavigationUI call internally creates its own NavOptions with these settings:

NavOptions.Builderbuilder=newNavOptions.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);

Unfortunately the method does not yet take a NavOptions.Builder as an argument, but you can create an utility class based on the Android source code to mimic the functionality:

publicclassNavigationUIHelper {
    publicstaticbooleanonNavDestinationSelected(@NonNull MenuItem item,
                                                   @NonNull NavController navController,
                                                   @NonNull NavOptions.Builder builder) {
        if ((item.getOrder() & Menu.CATEGORY_SECONDARY) == 0) {
            NavDestinationdestination= findStartDestination(navController.getGraph());
            builder.setPopUpTo(destination.getId(), false);
        }
        NavOptionsoptions= builder.build();
        try {
            navController.navigate(item.getItemId(), null, options);
            returntrue;
        } catch (IllegalArgumentException e) {
            returnfalse;
        }
    }

    // Need to copy this private method as wellprivatestatic NavDestination findStartDestination(@NonNull NavGraph graph) {
        NavDestinationstartDestination= graph;
        while (startDestination instanceof NavGraph) {
            NavGraphparent= (NavGraph) startDestination;
            startDestination = parent.findNode(parent.getStartDestination());
        }
        return startDestination;
    }
}

Finally, in your activity you can now replace the call to NavigationUI with the one implemented in NavigationUIHelper:

@OverridepublicbooleanonNavigationItemSelected(@NonNull MenuItem item) {
    NavHostnavHost= Navigation.findNavController(this, R.id.your_nav_host_fragment);
    NavOptions.Builderbuilder=newNavOptions.Builder()
                .setLaunchSingleTop(true)
                .setEnterAnim(R.anim.custom_enter)
                .setExitAnim(R.anim.custom_exit)
                .setPopEnterAnim(R.anim.custom_pop_enter)
                .setPopExitAnim(R.anim.custom_pop_exit);
    return NavigationUIHelper.onNavDestinationSelected(item, navHost, builder);
}

This should allow you to change the drawer transition animations according to your liking without having to replace the Navigation component.

Post a Comment for "Android Navigation Component Pop To Transition Issue"