I'm implementing a "press to reveal" transition us...
# compose
s
I'm implementing a "press to reveal" transition using
AnimatedContent
, so that the blue square goes away when pressed, and returns back when the press is released (as shown in the first part of the video). However, when the press is released before the transition ends, the red square starts animating instead, but it really shouldn't (second part of the video) Is there a mistake on my side (code in 🧵) or is it a bug?
Copy code
var flag by remember { mutableStateOf(false) }

AnimatedContent(
    targetState = flag,
    label = "",
    transitionSpec = {
        if (false isTransitioningTo true) {
            ContentTransform(
                targetContentEnter = EnterTransition.None,
                initialContentExit = slideOutOfContainer(AnimatedContentTransitionScope.SlideDirection.Start, animationSpec = tween(durationMillis = 500)),
                targetContentZIndex = -1.0f,
                sizeTransform = SizeTransform(clip = false)
            )
        } else {
            ContentTransform(
                targetContentEnter = slideIntoContainer(AnimatedContentTransitionScope.SlideDirection.End),
                initialContentExit = ExitTransition.Hold,
                targetContentZIndex = 0.0f,
                sizeTransform = SizeTransform(clip = false)
            )
        }
    },
    modifier = Modifier
        .pointerInput(Unit) {
            detectTapGestures(onPress = {
                flag = true
                tryAwaitRelease()
                flag = false
            })
        }
        .fillMaxSize()
) { flag ->
   Spacer(
       modifier = Modifier
           .wrapContentSize(Alignment.Center)
           .size(256.dp)
           .background(if (flag) Color.Red else Color.Blue)
   )
}
As you can see, it looks like the red square uses
slideOutOfContainer
, but the
initialContent
is attached to
false
, which renders the blue square
d
That doesn't look like the intended behavior. Please file a bug. Thanks!
1
s
Done: https://issuetracker.google.com/issues/298703882 For visibility, here's another
AnimatedContent
bug I reported a month ago: https://issuetracker.google.comh/issues/294408579
d
Thanks @ste 🙏 . I'll take a look at both.
🙌 1
s
@Doris Liu I think there is a general issue about the inability of animation APIs to correctly handle state changes when an animation is still running 😅 It seems only two animations can be handled at any given time - any previous state gets suddenly removed from the composition. Sample:
Copy code
var i by remember { mutableIntStateOf(0) }

AnimatedContent(
    targetState = i,
    label = "",
    transitionSpec = {
        val direction = AnimatedContentTransitionScope.SlideDirection.Down
        val animationSpec = tween<IntOffset>(durationMillis = 1000)

        slideIntoContainer(direction, animationSpec) togetherWith
                slideOutOfContainer(direction, animationSpec)
    },
    modifier = Modifier
        .clickable { i = (i + 1) % 3 }
        .fillMaxSize()
) { i ->
    Spacer(
        modifier = Modifier
            .fillMaxSize()
            .background(when (i) {
                0 -> Color.Red
                1 -> Color.Blue
                2 -> Color.Green
                else -> TODO()
            })
    )
}
Is it something the team is already aware of? I can definitely file an issue
d
What happened here is that when an animation is interrupted (i.e. the enter transition that became exit), we use spring animation to ensure a smooth interruption handling. As a result, that animation can be much faster than the animation that you explicitly defined: 1s tween
s
It makes sense to hasten the animation when the enter transition becomes the exit, but I wouldn't expect to see the white background (given the
Modifier.fillMaxSize()
)... I attached four contiguous frames of the recording (45ms difference in between): First frame: green in sliding from top, blue is sliding to bottom; the next state request (red) is about to get dispatched; Second frame: green is advanced by the expected distance, but blue is already disappeared (background visible); Third frame: red is just visible at the top, green is advanced by a big distance (background visible); Four frame: red is still at the top, green is advanced by a big distance again (background visible). Of course I don't know whether this is "unfixable" or whatever, it just doesn't look good 😅 - it really seems the transitions go "out of sync"