blob: 78211ea77f5456d78d3db3718ba5f11bd5c33009 [file] [log] [blame]
package com.airbnb.lottie.compose
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.platform.LocalContext
import com.airbnb.lottie.LottieComposition
import com.airbnb.lottie.utils.Utils
/**
* Returns a [LottieAnimationState] representing the progress of an animation.
*
* This is the declarative version of [rememberLottieAnimatable] and [LottieAnimation].
*
* @param composition The composition to render. This should be retrieved with [rememberLottieComposition].
* @param isPlaying Whether or not the animation is currently playing. Note that the internal
* animation may end due to reaching the target iterations count. If that happens,
* the animation may stop even if this is still true. You can observe the returned
* [LottieAnimationState.isPlaying] to determine whether the underlying animation
* is still playing.
* @param restartOnPlay If isPlaying switches from false to true, restartOnPlay determines whether
* the progress and iteration gets reset.
* @param clipSpec A [LottieClipSpec] that specifies the bound the animation playback
* should be clipped to.
* @param speed The speed the animation should play at. Numbers larger than one will speed it up.
* Numbers between 0 and 1 will slow it down. Numbers less than 0 will play it backwards.
* @param iterations The number of times the animation should repeat before stopping. It must be
* a positive number. [LottieConstants.IterateForever] can be used to repeat forever.
* @param cancellationBehavior The behavior that this animation should have when cancelled. In most cases,
* you will want it to cancel immediately. However, if you have a state based
* transition and you want an animation to finish playing before moving on to
* the next one then you may want to set this to [LottieCancellationBehavior.OnIterationFinish].
* @param ignoreSystemAnimatorScale By default, Lottie will respect the system animator scale set in developer options or set to 0
* by things like battery saver mode. When set to 0, the speed will effectively become [Integer.MAX_VALUE].
* Set this to false if you want to ignore the system animator scale and always default to normal speed.
*/
@Composable
fun animateLottieCompositionAsState(
composition: LottieComposition?,
isPlaying: Boolean = true,
restartOnPlay: Boolean = true,
clipSpec: LottieClipSpec? = null,
speed: Float = 1f,
iterations: Int = 1,
cancellationBehavior: LottieCancellationBehavior = LottieCancellationBehavior.Immediately,
ignoreSystemAnimatorScale: Boolean = false,
): LottieAnimationState {
require(iterations > 0) { "Iterations must be a positive number ($iterations)." }
require(speed.isFinite()) { "Speed must be a finite number. It is $speed." }
val animatable = rememberLottieAnimatable()
var wasPlaying by remember { mutableStateOf(isPlaying) }
// Dividing by 0 correctly yields Float.POSITIVE_INFINITY here.
val actualSpeed = if (ignoreSystemAnimatorScale) speed else (speed / Utils.getAnimationScale(LocalContext.current))
LaunchedEffect(
composition,
isPlaying,
clipSpec,
actualSpeed,
iterations,
) {
if (isPlaying && !wasPlaying && restartOnPlay) {
animatable.resetToBeginning()
}
wasPlaying = isPlaying
if (!isPlaying) return@LaunchedEffect
animatable.animate(
composition,
iterations = iterations,
speed = actualSpeed,
clipSpec = clipSpec,
initialProgress = animatable.progress,
continueFromPreviousAnimate = false,
cancellationBehavior = cancellationBehavior,
)
}
return animatable
}