1 package com.airbnb.lottie.compose
2
3 import androidx.compose.runtime.Composable
4 import androidx.compose.runtime.LaunchedEffect
5 import androidx.compose.runtime.getValue
6 import androidx.compose.runtime.mutableStateOf
7 import androidx.compose.runtime.remember
8 import androidx.compose.runtime.setValue
9 import androidx.compose.ui.platform.LocalContext
10 import com.airbnb.lottie.LottieComposition
11 import com.airbnb.lottie.utils.Utils
12
13 /**
14 * Returns a [LottieAnimationState] representing the progress of an animation.
15 *
16 * This is the declarative version of [rememberLottieAnimatable] and [LottieAnimation].
17 *
18 * @param composition The composition to render. This should be retrieved with [rememberLottieComposition].
19 * @param isPlaying Whether or not the animation is currently playing. Note that the internal
20 * animation may end due to reaching the target iterations count. If that happens,
21 * the animation may stop even if this is still true. You can observe the returned
22 * [LottieAnimationState.isPlaying] to determine whether the underlying animation
23 * is still playing.
24 * @param restartOnPlay If isPlaying switches from false to true, restartOnPlay determines whether
25 * the progress and iteration gets reset.
26 * @param reverseOnRepeat Defines what this animation should do when it reaches the end. This setting
27 * is applied only when [iterations] is either greater than 0 or [LottieConstants.IterateForever].
28 * Defaults to `false`.
29 * @param clipSpec A [LottieClipSpec] that specifies the bound the animation playback
30 * should be clipped to.
31 * @param speed The speed the animation should play at. Numbers larger than one will speed it up.
32 * Numbers between 0 and 1 will slow it down. Numbers less than 0 will play it backwards.
33 * @param iterations The number of times the animation should repeat before stopping. It must be
34 * a positive number. [LottieConstants.IterateForever] can be used to repeat forever.
35 * @param cancellationBehavior The behavior that this animation should have when cancelled. In most cases,
36 * you will want it to cancel immediately. However, if you have a state based
37 * transition and you want an animation to finish playing before moving on to
38 * the next one then you may want to set this to [LottieCancellationBehavior.OnIterationFinish].
39 * @param ignoreSystemAnimatorScale By default, Lottie will respect the system animator scale set in developer options or set to 0
40 * by things like battery saver mode. When set to 0, the speed will effectively become [Integer.MAX_VALUE].
41 * Set this to false if you want to ignore the system animator scale and always default to normal speed.
42 */
43 @Composable
animateLottieCompositionAsStatenull44 fun animateLottieCompositionAsState(
45 composition: LottieComposition?,
46 isPlaying: Boolean = true,
47 restartOnPlay: Boolean = true,
48 reverseOnRepeat: Boolean = false,
49 clipSpec: LottieClipSpec? = null,
50 speed: Float = 1f,
51 iterations: Int = 1,
52 cancellationBehavior: LottieCancellationBehavior = LottieCancellationBehavior.Immediately,
53 ignoreSystemAnimatorScale: Boolean = false,
54 useCompositionFrameRate: Boolean = false,
55 ): LottieAnimationState {
56 require(iterations > 0) { "Iterations must be a positive number ($iterations)." }
57 require(speed.isFinite()) { "Speed must be a finite number. It is $speed." }
58
59 val animatable = rememberLottieAnimatable()
60 var wasPlaying by remember { mutableStateOf(isPlaying) }
61
62 // Dividing by 0 correctly yields Float.POSITIVE_INFINITY here.
63 val actualSpeed = if (ignoreSystemAnimatorScale) speed else (speed / Utils.getAnimationScale(LocalContext.current))
64
65 LaunchedEffect(
66 composition,
67 isPlaying,
68 clipSpec,
69 actualSpeed,
70 iterations,
71 ) {
72 if (isPlaying && !wasPlaying && restartOnPlay) {
73 animatable.resetToBeginning()
74 }
75 wasPlaying = isPlaying
76 if (!isPlaying) return@LaunchedEffect
77
78 animatable.animate(
79 composition,
80 iterations = iterations,
81 reverseOnRepeat = reverseOnRepeat,
82 speed = actualSpeed,
83 clipSpec = clipSpec,
84 initialProgress = animatable.progress,
85 continueFromPreviousAnimate = false,
86 cancellationBehavior = cancellationBehavior,
87 useCompositionFrameRate = useCompositionFrameRate,
88 )
89 }
90
91 return animatable
92 }
93