voyager icon indicating copy to clipboard operation
voyager copied to clipboard

Transitions in between Tab Navigator

Open ShivamKumarJha opened this issue 2 years ago • 2 comments

Hi, Is there any way to have transitions such as slide or fade in between tab navigation? Thanks

ShivamKumarJha avatar Nov 29 '23 07:11 ShivamKumarJha

I'm able to achieve transitions in between tabs with some source mode modifications. However this is not restoring the previous saved state.

class TabNavigator internal constructor(
    internal val navigator: Navigator
) {

    var current: Tab
        get() = navigator.lastItem as Tab
        set(tab) {
            lastEvent =
                if (tab.options.index >= current.options.index) StackEvent.Push else StackEvent.Pop
            navigator.replaceAll(tab)
        }

    var lastEvent: StackEvent = StackEvent.Push


    @Composable
    fun saveableState(
        key: String,
        tab: Tab = current,
        content: @Composable () -> Unit
    ) {
        navigator.saveableState(key, tab, content = content)
    }
}

@Composable
fun SlideTransition(
    navigator: TabNavigator,
    modifier: Modifier = Modifier,
    orientation: SlideOrientation = SlideOrientation.Horizontal,
    animationSpec: FiniteAnimationSpec<IntOffset> = spring(
        stiffness = Spring.StiffnessMediumLow,
        visibilityThreshold = IntOffset.VisibilityThreshold
    ),
    content: TabNavigatorContent = { it.current.Content() }
) {
    ScreenTransition(
        navigator = navigator,
        modifier = modifier,
        content = content,
        transition = {
            val (initialOffset, targetOffset) = when (navigator.lastEvent) {
                StackEvent.Pop -> ({ size: Int -> -size }) to ({ size: Int -> size })
                else -> ({ size: Int -> size }) to ({ size: Int -> -size })
            }

            when (orientation) {
                SlideOrientation.Horizontal ->
                    slideInHorizontally(animationSpec, initialOffset) togetherWith
                            slideOutHorizontally(animationSpec, targetOffset)

                SlideOrientation.Vertical ->
                    slideInVertically(animationSpec, initialOffset) togetherWith
                            slideOutVertically(animationSpec, targetOffset)
            }
        }
    )
}

@Composable
fun ScreenTransition(
    navigator: TabNavigator,
    transition: AnimatedContentTransitionScope<Tab>.() -> ContentTransform,
    modifier: Modifier = Modifier,
    content: TabNavigatorContent = { it.current.Content() }
) {
    AnimatedContent(
        targetState = navigator.current,
        transitionSpec = transition,
        modifier = modifier
    ) { tab ->
        navigator.saveableState("transition", tab) {
            content(navigator)
        }
    }
}

ShivamKumarJha avatar Nov 29 '23 07:11 ShivamKumarJha

I was able to get state-restoration working with a small modification:

@Composable
fun ScreenTransition(
    navigator: TabNavigator,
    transition: AnimatedContentTransitionScope<Tab>.() -> ContentTransform,
    modifier: Modifier = Modifier,
-    content: TabNavigatorContent = { it.current.Content() }
) {
    AnimatedContent(
        targetState = navigator.current,
        transitionSpec = transition,
        modifier = modifier
    ) { tab ->
        navigator.saveableState("transition", tab) {
-            content(navigator)
+            tab.Content()
        }
    }
}

cedrickcooke avatar Mar 13 '24 17:03 cedrickcooke