https://kotlinlang.org logo
Title
a

Alex

02/23/2023, 7:47 AM
Hey, how can I get notified of animation start/end inside of an
AnimatedVisibility
? Code in 🧵
Right now I have:
@Composable
public inline fun Transition<EnterExitState>.ListenerEffect(
    noinline transitionSpec: @Composable Transition.Segment<EnterExitState>.() -> FiniteAnimationSpec<Int> = {
        spring(visibilityThreshold = 1)
    },
    label: String = "ListenerEffect",
    onEnterStart: () -> Unit = {},
    onEnterEnd: () -> Unit = {},
    onExitStart: () -> Unit = {},
    onExitEnd: () -> Unit = {},
) {
    val animationProgress by animateValue(Int.VectorConverter, transitionSpec, label) { enterExitState ->
        when (enterExitState) {
            EnterExitState.PreEnter -> 200
            EnterExitState.Visible -> 100
            EnterExitState.PostExit -> 0
        }
    }
    when (animationProgress) {
        200 -> onEnterStart()
        100 -> when (currentState) {
            EnterExitState.PreEnter -> when (targetState) {
                EnterExitState.Visible -> onEnterEnd()
                else -> Unit // ignore
            }
            EnterExitState.Visible -> when (targetState) {
                EnterExitState.PostExit -> onExitStart()
                else -> Unit // ignore
            }
            else -> Unit // ignore
        }
        0 -> onExitEnd()
    }
}
Which feels way too akward to be used in production
Jetpack Compose itself offers this helpful TODO qq
d

Doris Liu

02/23/2023, 7:37 PM
Are you using AnimatedVisibility as an extension function on a Transition? If not, you could use the
AnimatedVisibility
overload that takes a MutableTransitionState, and observe the state change in a snapshotFlow
Something like this:
val visibleState = remember { MutableTransitionState(false)}
            visibleState.targetState = ..
            LaunchedEffect(Unit) {
                snapshotFlow { Pair(visibleState.currentState, visibleState.targetState) }.collect {
                    if (it.first == it.second) {
                        if (visibleState.currentState) {
                            // enter finished
                        } else {
                            // exit finished
                        }
                    } else {
                        if (visibleState.targetState) {
                            // enter started
                        } else {
                            // exit started
                        }
                    }
                }
            }
            AnimatedVisibility(visibleState = visibleState) {
                ...
            }
a

Alex

02/23/2023, 7:54 PM
I’m using the extension and unfortunately cannot change that part as it is inside of a library. I’ll check if I can adapt your code for my purposes though, somehow.
d

Doris Liu

02/23/2023, 8:01 PM
The code could be easily adapted to observe
Transition.current/targetState
instead.