Многократно используемые анимации в навигационном графике библиотеки навигации Android

Интересно, есть ли способ создать повторно используемый набор анимаций для навигационного графика. Что-то вроде стиля, который содержит все свойства анимации, а не повторяет одни и те же снова и снова.

Что я имею:

<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" />

С большим навигационным графом, уменьшение этой повторяющейся настройки анимации сделало бы ее намного более управляемой.


person Tyler Turnbull    schedule 21.05.2021    source источник
comment
Отвечает ли это на ваш вопрос? Как определить анимацию по умолчанию для действий навигации?   -  person Sam Chen    schedule 23.05.2021


Ответы (1)


Один из способов сделать это — изменить анимации навигации по умолчанию и установить нужные анимации в качестве навигации по умолчанию для ваших фрагментов. Для этого вам нужно будет обновить параметры навигации Процесс:

<androidx.fragment.app.FragmentContainerView
    app:defaultNavHost="true"
    ...
    android:name="androidx.navigation.fragment.NavHostFragment"/>

to:

<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
                }
            }
        }

}

Здесь просто измените значение анимации в navoptions, и все готово.

person Kashif Mehmood    schedule 23.05.2021