Skip to content

Commit

Permalink
Add extension for overriding navigation animations and getting an Ani…
Browse files Browse the repository at this point in the history
…matedVisibilityScope back as a receiver, which is useful for shared element transitions.
  • Loading branch information
isaac-udy committed May 1, 2024
1 parent 3f3755a commit f3c91f2
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package dev.enro.core.compose

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.AnimatedVisibilityScope
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition
import androidx.compose.animation.ExperimentalAnimationApi
import androidx.compose.animation.core.MutableTransitionState
import androidx.compose.animation.core.Transition
import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeOut
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.ui.platform.LocalInspectionMode
Expand Down Expand Up @@ -69,4 +74,41 @@ public fun OverrideNavigationAnimations(
)
onDispose { }
}
}
}

@OptIn(ExperimentalAnimationApi::class)
@Composable
@AdvancedEnroApi
public fun OverrideNavigationAnimations(
enter: EnterTransition,
exit: ExitTransition,
content: @Composable AnimatedVisibilityScope.() -> Unit
) {
// If we are in inspection mode, we need to ignore this call, as it relies on items like navigationContext
// which are only available in actual running applications
val isInspection = LocalInspectionMode.current
if (isInspection) return

val navigationContext = navigationContext
val destination = navigationContext.contextReference as ComposableDestination
DisposableEffect(Unit) {
destination.owner.animationOverride = NavigationAnimation.Composable(
enter = EnterTransition.None,
// We need a little fade out here to keep the animation active while the animated visibility below has a chance to run
// and attach child transitions. This is a bit of a hack, but it's the only way to ensure that child exit transitions
// are fully run.
exit = fadeOut(
targetAlpha = 0.99f,
animationSpec = tween(512),
),
)
onDispose { }
}
navigationTransition.AnimatedVisibility(
visible = {it},
enter = enter,
exit = exit,
) {
content()
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package dev.enro.tests.application.compose.results

import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
Expand All @@ -22,6 +26,7 @@ import dev.enro.annotations.NavigationDestination
import dev.enro.core.NavigationKey
import dev.enro.core.close
import dev.enro.core.closeWithResult
import dev.enro.core.compose.OverrideNavigationAnimations
import dev.enro.core.compose.dialog.DialogDestination
import dev.enro.core.compose.navigationHandle
import dev.enro.core.compose.rememberNavigationContainer
Expand Down Expand Up @@ -72,10 +77,7 @@ class ComposeManagedResultViewModel(
flow = {
val firstResult = push { ComposeManagedResultFlow.FirstResult() }
val presentedResult = present { ComposeManagedResultFlow.PresentedResult() }
val secondResult = push {
default("default")
ComposeManagedResultFlow.SecondResult()
}
val secondResult = push { ComposeManagedResultFlow.SecondResult() }
val transientResult = push {
transient()
dependsOn(secondResult)
Expand Down Expand Up @@ -173,17 +175,24 @@ fun SecondResultScreen() {

@NavigationDestination(ComposeManagedResultFlow.TransientResult::class)
@Composable
fun SkipOnBackResultScreen() {
fun TransientResultScreen() {
val navigation = navigationHandle<ComposeManagedResultFlow.TransientResult>()
TitledColumn(title = "Transient Result") {
Text(text = "This screen will only be displayed if the result from the second screen has changed")

Button(onClick = { navigation.closeWithResult("A") }) {
Text("Continue (A)")
}
OverrideNavigationAnimations(
enter = fadeIn() + slideInVertically { it / 4 },
exit = fadeOut() + slideOutVertically { it / 4 },
) {
TitledColumn(title = "Transient Result") {
Text(
text = "This screen will only be displayed if the result from the second screen has changed"
)

Button(onClick = { navigation.closeWithResult("A") }) {
Text("Continue (A)")
}

Button(onClick = { navigation.closeWithResult("B") }) {
Text("Continue (B)")
Button(onClick = { navigation.closeWithResult("B") }) {
Text("Continue (B)")
}
}
}
}
Expand Down

0 comments on commit f3c91f2

Please sign in to comment.