adrielcafe / voyager

🛸 A pragmatic navigation library for Jetpack Compose
https://voyager.adriel.cafe
MIT License
2.27k stars 109 forks source link

Choose Different Animation Transitions Based on Different Screens #351

Open KAMO030 opened 2 months ago

KAMO030 commented 2 months ago

Hi,If I want to choose different animation transitions based on different screens, is there a better approach to achieve this? The simple way is as follows.:

@Composable
fun App() {
    Navigator(A) {
        ScreenTransition(
            navigator = it,
            transition = {
                when {
                    // Any -> A || A ->  Any
                    initialState is A || targetState is A  -> 
                        fadeIn() togetherWith slideOutHorizontally()
                    // B  ->  C || C  ->  B
                   (initialState is B && targetState is C) || (initialState is C && targetState is B) ->
                        fadeIn() togetherWith slideOutHorizontally()
                    // D  -> E
                     initialState is D && targetState is E  -> 
                        expandIn() togetherWith scaleOut()
                    // E  ->  D
                    initialState is E && targetState is D  -> 
                        slideInVertically() togetherWith slideOutHorizontally()
                    else -> ContentTransform(EnterTransition.None, ExitTransition.None)
                }
            }
        )
    }
}

However, it looks quite messy, so I've added some extension methods to simplify it:

@Composable
fun App() {
    Navigator(A) {
        SelectableScreenTransition(it){
                when {
                    isTransitioning<A>() -> fadeIn() togetherWith slideOutHorizontally()
                    isTransitioningOn<B,C>() ->  fadeIn() togetherWith slideOutHorizontally()
                    isTransitioningFromTo<D,E>() -> expandIn() togetherWith scaleOut()
                    isTransitioningFromTo<E,D>() ->  slideInVertically() togetherWith slideOutHorizontally()
                    else -> ContentTransform(EnterTransition.None, ExitTransition.None)
                }
            }
    }
}

extension methods:

@Composable
fun SelectableScreenTransition(
    navigator: Navigator,
    modifier: Modifier = Modifier,
    transition : AnimatedContentTransitionScope<Screen>.() -> ContentTransform,
) {
    ScreenTransition(
        navigator = navigator,
        modifier = modifier,
        transition = transition
    )
}

// Any -> A || A -> Any
inline fun <reified T : Screen> AnimatedContentTransitionScope<Screen>.isTransitioning() =
    isTransitioningTo<T>() || isTransitioningFrom<T>()

// A- > B || B -> A
inline fun <reified T : Screen, reified K : Screen> AnimatedContentTransitionScope<Screen>.isTransitioningOn() =
    isTransitioningFromTo<T, K>() || isTransitioningFromTo<K, T>()

// A-> B
inline fun <reified T : Screen, reified K : Screen> AnimatedContentTransitionScope<Screen>.isTransitioningFromTo() =
    isTransitioningTo<T>() && isTransitioningFrom<K>()

// A->A || B-> A
inline fun <reified T : Screen> AnimatedContentTransitionScope<Screen>.isTransitioningTo() =
    targetState is T

// A -> A || A-> B
inline fun <reified T : Screen> AnimatedContentTransitionScope<Screen>.isTransitioningFrom() =
    initialState is T

If there are better suggestions, I would be grateful if you could kindly offer your guidance. If you consider my proposal feasible, I would appreciate it if it could be included in the library for more people to utilize.

tethridge commented 2 months ago

Check out this talk where the speaker shows how they did custom transitions per Screen. https://www.droidcon.com/2022/08/02/painless-typesafe-jetpack-compose-navigation-with-voyager/

markusressel commented 4 weeks ago

Do I understand the talk correctly, that we have implement all of this ourselves from scratch? If so, is there any plan to integrate this ScreenBasedTransition, the CustomScreenTransition interface, or anything else in the future?

Thx!