Android Navigation Component pop to transition issue

前端 未结 2 799
广开言路
广开言路 2020-12-29 08:05

I have 2 actions

Action1

 

        
相关标签:
2条回答
  • 2020-12-29 08:32

    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.

    override fun onCreateAnimation(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)
        }
        return super.onCreateAnimation(transit, enter, nextAnim)
    }
    

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

    0 讨论(0)
  • 2020-12-29 08:37

    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:

    <menu xmlns:android="http://schemas.android.com/apk/res/android">
    
        ...
    
        <item android:id="@+id/example_id" ... />
    </menu>
    
    <navigation xmlns:android="http://schemas.android.com/apk/res/android" ... >
    
        ...
    
        <fragment android: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:

    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
        NavHost navHost = 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.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);
    

    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:

    public class NavigationUIHelper {
        public static boolean onNavDestinationSelected(@NonNull MenuItem item,
                                                       @NonNull NavController navController,
                                                       @NonNull NavOptions.Builder builder) {
            if ((item.getOrder() & Menu.CATEGORY_SECONDARY) == 0) {
                NavDestination destination = findStartDestination(navController.getGraph());
                builder.setPopUpTo(destination.getId(), false);
            }
            NavOptions options = builder.build();
            try {
                navController.navigate(item.getItemId(), null, options);
                return true;
            } catch (IllegalArgumentException e) {
                return false;
            }
        }
    
        // Need to copy this private method as well
        private static NavDestination findStartDestination(@NonNull NavGraph graph) {
            NavDestination startDestination = graph;
            while (startDestination instanceof NavGraph) {
                NavGraph parent = (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:

    @Override
    public boolean onNavigationItemSelected(@NonNull MenuItem item) {
        NavHost navHost = Navigation.findNavController(this, R.id.your_nav_host_fragment);
        NavOptions.Builder builder = new NavOptions.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.

    0 讨论(0)
提交回复
热议问题