Thread
#compose
    s

    Se7eN

    1 year ago
    I'm animating the progress of this meter from 0 to 100 infinitely. When some data from the network is loaded, containing the progress value, I want it to transition to that value and stop the infinite animation. How can I achieve this? Code in thread.
    val infiniteTransition = rememberInfiniteTransition()
    val progress by infiniteTransition.animateFloat(
        initialValue = 0f,
        targetValue = 100f,
        animationSpec = infiniteRepeatable(
            animation = tween(1000, easing = LinearEasing),
            repeatMode = RepeatMode.Reverse
        )
    )
    Tash

    Tash

    1 year ago
    To control the animation imperatively like that, might need to use
    Animatable
    instead, since it exposes a
    stop()
    s

    Se7eN

    1 year ago
    So I used
    updateTransition
    and came up with this. It's working fine, just wanna make sure if I did it right?
    Doris Liu

    Doris Liu

    1 year ago
    I don't think
    updateTransition
    is the best API for this use case.
    Transition
    expects a value associated with each state, and animates to that value when state changes. The initial infinite animation between 0-100 isn't exactly a state.
    Animatable
    would be more suitable for your use case, you can start with an
    animateTo
    using an infinite animation spec, and interrupt it any time with a new target based on the network data.
    Tash

    Tash

    1 year ago
    The initial infinite animation between 0-100 isn’t exactly a state
    To add to that, looks like the snippet is transforming between
    MeterHeadState
    and a float, clearly indicating that you are trying to make the 0-100 animation into a state just to make it work with
    updateTransition()
    .
    s

    Se7eN

    1 year ago
    Got it. I'll use
    Animatable
    and remove the
    MeterHeadState
    . Thank you both!
    val progress = remember { Animatable(0f) }
    LaunchedEffect(index) {
        if (index != null) {
            progress.animateTo(
                targetValue = index.value.toFloat(),
                animationSpec = spring(
                    Spring.DampingRatioMediumBouncy,
                    stiffness = Spring.StiffnessVeryLow
                )
            )
        } else {
            progress.animateTo(
                targetValue = 100f,
                animationSpec = infiniteRepeatable(
                    animation = keyframes {
                        durationMillis = 800
                        0f at 0 with FastOutSlowInEasing
                        100f at 800 with FastOutSlowInEasing
                    },
                    repeatMode = RepeatMode.Reverse
                )
            )
        }
    }
    So I guess I'm doing it right now
    Doris Liu

    Doris Liu

    1 year ago
    Much cleaner! 👏
    s

    Se7eN

    1 year ago
    Sorry for bothering again but is it fine to just return the value like this:
    @Composable
    private fun animatedProgress(index: FGIndex?): Float {
        val progress = remember { Animatable(0f) }
        LaunchedEffect(index) {
            if (index != null) {
                progress.animateTo(
                    targetValue = index.value.toFloat(),
                    animationSpec = ProgressToIndexSpec
                )
            } else {
                progress.animateTo(
                    targetValue = 100f,
                    animationSpec = ProgressInfiniteSpec
                )
            }
        }
    
        return progress.value
    }
    Doris Liu

    Doris Liu

    1 year ago
    No bother at all. That looks fine. Though I would defer the value read until later whenever possible - The location of state read determines the scope of invalidation. If the progress only needs to be read during draw, I'd return a
    State<Float>
    here instead (i.e.
    progress.asState()
    )
    s

    Se7eN

    1 year ago
    Oh, I get it now. Thanks for all the help 🙂