Search code examples
androidandroid-jetpack-composelottie

How do I update a LottieCompose clipSpec at runtime


I have a Lottie animation that I want to start then when it gets to a certain frame I want to loop from frame X to frame Y.

The issue I am running up against is that I cant seem to figure out how to update the clipSpec at runtime with LottieCompose as clipSpec cannot be reassigned.

I was able to do this no problem with normal XML layout based Lottie like this

loading_animation.addAnimatorUpdateListener {

    if(initialLoad && loading_animation.frame == 15){
        initialLoad = false
        startTime = System.currentTimeMillis()
        loading_animation.setMinAndMaxFrame(15,28)
    }

    if(!initialLoad && authenticated && System.currentTimeMillis() >= (startTime+1000)){
        loading_animation.pauseAnimation()
        startActivity()
    }

}

here is my LottieCompose code I have so far

val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.sun_icon))
val animatable = rememberLottieAnimatable()
val progress by animateLottieCompositionAsState(composition, iterations = LottieConstants.IterateForever)
LottieAnimation(composition = composition, progress = progress, modifier = Modifier.wrapContentSize())

Solution

  • clipSpec can be specified with animateLottieCompositionAsState. You can update it just like any other state in Compose: create a state variable and update it with some action/side-effect.

    Learn more about state in Compose documentation, including this youtube video, which explains the basic principles.

    getFrameForProgress returns a frame in Float, I am not sure if it is safe to convert it to Int and compare equals (is it guaranteed that every frame is rendered? on slow devices it might not be), so my comparison code looks not too nice.

    val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw. sun_icon))
    var clipSpec by remember { mutableStateOf<LottieClipSpec?>(null)}
    val progress by animateLottieCompositionAsState(
        composition = composition,
        clipSpec = clipSpec,
        iterations = LottieConstants.IterateForever
    )
    LottieAnimation(
        composition = composition,
        progress = progress,
        modifier = Modifier.wrapContentSize()
    )
    var initialLoad by remember { mutableStateOf(true) }
    if (initialLoad && composition?.getFrameForProgress(progress)?.let { it >= 15f } == true) {
        SideEffect {
            initialLoad = false
            clipSpec = LottieClipSpec.Frame(
                min = 15,
                max = 28
            )
        }
    }