Android导航库nav graph中的可重用动画

Android导航库nav graph中的可重用动画,android,android-jetpack,android-navigation,android-native-library,Android,Android Jetpack,Android Navigation,Android Native Library,想知道是否有一种方法可以为导航图创建一组可重用的动画。类似于包含所有动画属性的样式,而不是反复重复相同的属性 我所拥有的: <action android:id="@+id/toFragmentA" app:destination="@id/fragmentA" app:enterAnim="@anim/slide_in_right" app:exitAnim=&qu

想知道是否有一种方法可以为导航图创建一组可重用的动画。类似于包含所有动画属性的样式,而不是反复重复相同的属性

我所拥有的:

<action
        android:id="@+id/toFragmentA"
        app:destination="@id/fragmentA"
        app:enterAnim="@anim/slide_in_right"
        app:exitAnim="@anim/slide_out_left"
        app:popEnterAnim="@anim/slide_in_left"
        app:popExitAnim="@anim/slide_out_right" />
    <action
        android:id="@+id/toFragmentB"
        app:destination="@id/fragmentB"
        app:enterAnim="@anim/slide_in_right"
        app:exitAnim="@anim/slide_out_left"
        app:popEnterAnim="@anim/slide_in_left"
        app:popExitAnim="@anim/slide_out_right" />
    <action
        android:id="@+id/toFragmentC"
        app:destination="@id/fragmentC"
        app:enterAnim="@anim/slide_in_right"
        app:exitAnim="@anim/slide_out_left"
        app:popEnterAnim="@anim/slide_in_left"
        app:popExitAnim="@anim/slide_out_right" />
    <action
        android:id="@+id/toFragmentD"
        app:destination="@id/fragmentD"
        app:enterAnim="@anim/slide_in_right"
        app:exitAnim="@anim/slide_out_left"
        app:popEnterAnim="@anim/slide_in_left"
        app:popExitAnim="@anim/slide_out_right" />
    <action
        android:id="@+id/toFragmentE"
        app:destination="@id/fragmentE"
        app:enterAnim="@anim/slide_in_right"
        app:exitAnim="@anim/slide_out_left"
        app:popEnterAnim="@anim/slide_in_left"
        app:popExitAnim="@anim/slide_out_right" />

我想要什么

    <action
        android:id="@+id/toFragmentA"
        app:destination="@id/fragmentA"
        app:anim="@anim/slideInOut" />
    <action
        android:id="@+id/toFragmentB"
        app:destination="@id/fragmentB"
        app:anim="@anim/slideInOut" />
    <action
        android:id="@+id/toFragmentC"
        app:destination="@id/fragmentC"
        app:anim="@anim/slideInOut" />
    <action
        android:id="@+id/toFragmentD"
        app:destination="@id/fragmentD"
        app:anim="@anim/slideInOut" />
    <action
        android:id="@+id/toFragmentE"
        app:destination="@id/fragmentE"
        app:anim="@anim/slideInOut" />


使用大型导航图,减少重复的动画设置将使其更易于管理。

一种方法是更改默认导航动画,并将所需动画设置为片段的默认导航。为此,您必须更新导航选项 过程:


在这里,只需更改navoptions中的动画值,您就可以开始了

这是否回答了您的问题?
<androidx.fragment.app.FragmentContainerView
    app:defaultNavHost="true"
    ...
    android:name="androidx.navigation.fragment.NavHostFragment"/>
<androidx.fragment.app.FragmentContainerView
    app:defaultNavHost="true"
    ...
    android:name="your.app.package.fragments.MyNavHostFragment"/>
 package your.app.package.fragments

import android.content.Context
import android.os.Bundle
import androidx.fragment.app.FragmentManager
import androidx.navigation.*
import androidx.navigation.fragment.FragmentNavigator
import androidx.navigation.fragment.NavHostFragment
import your.app.package.R

// Those are navigation-ui (androidx.navigation.ui) defaults
// used in NavigationUI for NavigationView and BottomNavigationView.
// Set yours here
private val defaultNavOptions = navOptions {
    anim {
        enter = R.animator.nav_default_enter_anim
        exit = R.animator.nav_default_exit_anim
        popEnter = R.animator.nav_default_pop_enter_anim
        popExit = R.animator.nav_default_pop_exit_anim
    }
}

private val emptyNavOptions = navOptions {}

classMyNavHostFragment : NavHostFragment() {

    override fun onCreateNavController(navController: NavController) {
        super.onCreateNavController(navController)
        navController.navigatorProvider.addNavigator(
            // this replaces FragmentNavigator
            FragmentNavigatorWithDefaultAnimations(requireContext(), childFragmentManager, id)
        )
    }

}

/**
 * Needs to replace FragmentNavigator and replacing is done with name in annotation.
 * Navigation method will use defaults for fragments transitions animations.
 */
@Navigator.Name("fragment")
class FragmentNavigatorWithDefaultAnimations(
    context: Context,
    manager: FragmentManager,
    containerId: Int
) : FragmentNavigator(context, manager, containerId) {

    override fun navigate(
        destination: Destination,
        args: Bundle?,
        navOptions: NavOptions?,
        navigatorExtras: Navigator.Extras?
    ): NavDestination? {
        // this will try to fill in empty animations with defaults when no shared element transitions are set
        // https://developer.android.com/guide/navigation/navigation-animate-transitions#shared-element
        val shouldUseTransitionsInstead = navigatorExtras != null
        val navOptions = if (shouldUseTransitionsInstead) navOptions
        else navOptions.fillEmptyAnimationsWithDefaults()
        return super.navigate(destination, args, navOptions, navigatorExtras)
    }

    private fun NavOptions?.fillEmptyAnimationsWithDefaults(): NavOptions =
        this?.copyNavOptionsWithDefaultAnimations() ?: defaultNavOptions

    private fun NavOptions.copyNavOptionsWithDefaultAnimations(): NavOptions =
        let { originalNavOptions ->
            navOptions {
                launchSingleTop = originalNavOptions.shouldLaunchSingleTop()
                popUpTo(originalNavOptions.popUpTo) {
                    inclusive = originalNavOptions.isPopUpToInclusive
                }
                anim {
                    enter =
                        if (originalNavOptions.enterAnim == emptyNavOptions.enterAnim) defaultNavOptions.enterAnim
                        else originalNavOptions.enterAnim
                    exit =
                        if (originalNavOptions.exitAnim == emptyNavOptions.exitAnim) defaultNavOptions.exitAnim
                        else originalNavOptions.exitAnim
                    popEnter =
                        if (originalNavOptions.popEnterAnim == emptyNavOptions.popEnterAnim) defaultNavOptions.popEnterAnim
                        else originalNavOptions.popEnterAnim
                    popExit =
                        if (originalNavOptions.popExitAnim == emptyNavOptions.popExitAnim) defaultNavOptions.popExitAnim
                        else originalNavOptions.popExitAnim
                }
            }
        }

}