• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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