diff --git a/README.md b/README.md index 172e3925..2bdd3f40 100644 --- a/README.md +++ b/README.md @@ -30,24 +30,22 @@ Basic usage: val lottieData : String = // ... your lottie JSON -val composition = rememberLottieComposition(lottieData) +val composition by rememberLottieComposition(lottieData) LottieAnimation( composition = composition, - modifier = Modifier.size(300.dp) ) ``` With manual progress control: ```kotlin -val composition = rememberLottieComposition(lottieData) +val composition by rememberLottieComposition(lottieData) -val progress = animateLottieCompositionAsState(composition) +val progress by animateLottieCompositionAsState(composition) LottieAnimation( composition = composition, - progress = { progress.value }, - modifier = Modifier.size(300.dp) + progress = { progress }, ) ``` diff --git a/compottie/src/androidMain/kotlin/io/github/alexzhirkevich/compottie/LottieAnimation.android.kt b/compottie/src/androidMain/kotlin/io/github/alexzhirkevich/compottie/LottieAnimation.android.kt index 3588e9f1..efc7213f 100644 --- a/compottie/src/androidMain/kotlin/io/github/alexzhirkevich/compottie/LottieAnimation.android.kt +++ b/compottie/src/androidMain/kotlin/io/github/alexzhirkevich/compottie/LottieAnimation.android.kt @@ -2,9 +2,15 @@ package io.github.alexzhirkevich.compottie import androidx.compose.animation.core.RepeatMode import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.SideEffect import androidx.compose.runtime.State +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Size +import com.airbnb.lottie.Lottie import com.airbnb.lottie.compose.LottieCancellationBehavior import com.airbnb.lottie.compose.LottieCompositionSpec import com.airbnb.lottie.compose.animateLottieCompositionAsState @@ -14,44 +20,59 @@ import com.airbnb.lottie.compose.rememberLottieComposition actual class LottieComposition( - internal val composition : com.airbnb.lottie.LottieComposition? -) + internal val composition : com.airbnb.lottie.LottieComposition +) { + + actual val frameRate: Float + get() = composition.frameRate + + actual val duration: Float + get() = composition.duration / 1000 +} //actual val LottieComposition.duration : Float // get() = duration / 1000f @Composable -actual fun rememberLottieComposition(data : String) : LottieComposition { - val composition = rememberLottieComposition(LottieCompositionSpec.JsonString(data)).value +actual fun rememberLottieComposition(data : String) : State { - return remember(composition) { - LottieComposition(composition) + val state = remember { + mutableStateOf(null) } + + val composition by rememberLottieComposition(LottieCompositionSpec.JsonString(data)) + + LaunchedEffect(composition) { +// composition?.b + state.value = composition?.let(::LottieComposition) + } + + return state } @Composable actual fun LottieAnimation( - composition : LottieComposition, + composition : LottieComposition?, progress : () -> Float, modifier: Modifier, ) { com.airbnb.lottie.compose.LottieAnimation( modifier = modifier, - composition = composition.composition, + composition = composition?.composition, progress = progress ) } @Composable actual fun animateLottieCompositionAsState( - composition: LottieComposition, + composition: LottieComposition?, repeatMode: RepeatMode, cancellationBehavior: CancellationBehavior, isPlaying : Boolean, iterations : Int, ) : State { return animateLottieCompositionAsState( - composition = composition.composition, + composition = composition?.composition, reverseOnRepeat = repeatMode == RepeatMode.Reverse, iterations = iterations, restartOnPlay = true, diff --git a/compottie/src/commonMain/kotlin/io/github/alexzhirkevich/compottie/LottieAnimation.kt b/compottie/src/commonMain/kotlin/io/github/alexzhirkevich/compottie/LottieAnimation.kt index b364c2b1..f6c382ee 100644 --- a/compottie/src/commonMain/kotlin/io/github/alexzhirkevich/compottie/LottieAnimation.kt +++ b/compottie/src/commonMain/kotlin/io/github/alexzhirkevich/compottie/LottieAnimation.kt @@ -4,6 +4,7 @@ import androidx.compose.animation.core.RepeatMode import androidx.compose.runtime.Composable import androidx.compose.runtime.State import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Size enum class CancellationBehavior { /** @@ -22,7 +23,19 @@ enum class CancellationBehavior { /** * Holds animation data * */ -expect class LottieComposition +expect class LottieComposition { + + /** + * Animation frame per second rate + * */ + + val frameRate : Float + + /** + * Animation duration in seconds + * */ + val duration : Float +} ///** // * Animation duration in seconds @@ -35,7 +48,7 @@ expect class LottieComposition * @param data Lottie JSON string * */ @Composable -expect fun rememberLottieComposition(data : String) : LottieComposition +expect fun rememberLottieComposition(data : String) : State /** * State of the lottie animation progress @@ -51,7 +64,7 @@ expect fun rememberLottieComposition(data : String) : LottieComposition * */ @Composable expect fun animateLottieCompositionAsState( - composition: LottieComposition, + composition: LottieComposition?, repeatMode: RepeatMode = RepeatMode.Restart, cancellationBehavior: CancellationBehavior = CancellationBehavior.Immediately, isPlaying : Boolean = true, @@ -69,7 +82,7 @@ expect fun animateLottieCompositionAsState( * */ @Composable expect fun LottieAnimation( - composition : LottieComposition, + composition : LottieComposition?, progress : () -> Float, modifier: Modifier = Modifier ) @@ -88,7 +101,7 @@ expect fun LottieAnimation( * */ @Composable fun LottieAnimation( - composition: LottieComposition, + composition: LottieComposition?, modifier: Modifier = Modifier, repeatMode: RepeatMode = RepeatMode.Restart, cancellationBehavior: CancellationBehavior = CancellationBehavior.Immediately, diff --git a/compottie/src/skikoMain/kotlin/io/github/alexzhirkevich/compottie/LottieAnimation.skiko.kt b/compottie/src/skikoMain/kotlin/io/github/alexzhirkevich/compottie/LottieAnimation.skiko.kt index e562d08c..122a5c59 100644 --- a/compottie/src/skikoMain/kotlin/io/github/alexzhirkevich/compottie/LottieAnimation.skiko.kt +++ b/compottie/src/skikoMain/kotlin/io/github/alexzhirkevich/compottie/LottieAnimation.skiko.kt @@ -9,19 +9,26 @@ import androidx.compose.animation.core.rememberInfiniteTransition import androidx.compose.animation.core.repeatable import androidx.compose.animation.core.tween import androidx.compose.foundation.Canvas +import androidx.compose.foundation.LocalIndication +import androidx.compose.foundation.layout.defaultMinSize +import androidx.compose.foundation.layout.size import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.State import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableFloatStateOf +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberUpdatedState import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Size import androidx.compose.ui.graphics.drawscope.drawIntoCanvas import androidx.compose.ui.graphics.nativeCanvas +import androidx.compose.ui.platform.LocalDensity +import androidx.compose.ui.unit.DpSize import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.flow.onCompletion import kotlinx.coroutines.flow.takeWhile @@ -30,49 +37,72 @@ import org.jetbrains.skia.skottie.Animation import org.jetbrains.skia.sksg.InvalidationController import kotlin.math.roundToInt -actual typealias LottieComposition = Animation +actual class LottieComposition(internal val animation: Animation) { + actual val frameRate: Float + get() = animation.fPS + + /** + * Animation duration in seconds + * */ + actual val duration: Float + get() = animation.duration +} //actual val LottieComposition.duration : Float // get() = duration @Composable -actual fun rememberLottieComposition(data : String) : LottieComposition { - return remember(data) { Animation.makeFromString(data) } +actual fun rememberLottieComposition(data : String) : State { + return remember(data) { mutableStateOf(LottieComposition(Animation.makeFromString(data))) } } @Composable actual fun LottieAnimation( - composition : LottieComposition, + composition : LottieComposition?, progress : () -> Float, modifier: Modifier ) { - val animation = composition ?: return + val defaultSize = LocalDensity.current.run { + if (composition == null) + DpSize.Zero + else + DpSize( + composition.animation.width.toDp(), + composition.animation.height.toDp(), + ) + } + val invalidationController = remember { InvalidationController() } - Canvas(modifier) { + Canvas( + modifier + .size(defaultSize) + ) { drawIntoCanvas { - animation.seek(progress(), invalidationController) + if (composition != null) { + composition.animation.seek(progress(), invalidationController) - animation.render( - canvas = it.nativeCanvas, - dst = Rect.makeWH(size.width, size.height) - ) + composition.animation.render( + canvas = it.nativeCanvas, + dst = Rect.makeWH(size.width, size.height) + ) + } } } } @Composable actual fun animateLottieCompositionAsState( - composition: LottieComposition, + composition: LottieComposition?, repeatMode: RepeatMode, cancellationBehavior: CancellationBehavior, isPlaying : Boolean, iterations : Int, ) : State { - val duration = composition.duration.times(1000).roundToInt() + val duration = composition?.animation?.duration?.times(1000)?.roundToInt() ?: 0 val animationSpec = tween(duration, easing = LinearEasing) val progress = remember { diff --git a/example/shared/src/commonMain/kotlin/App.kt b/example/shared/src/commonMain/kotlin/App.kt index 571ebcb5..b2759d88 100644 --- a/example/shared/src/commonMain/kotlin/App.kt +++ b/example/shared/src/commonMain/kotlin/App.kt @@ -1,11 +1,17 @@ +import androidx.compose.foundation.border import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.size import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.unit.Dp import androidx.compose.ui.unit.dp import io.github.alexzhirkevich.compottie.LottieAnimation +import io.github.alexzhirkevich.compottie.animateLottieCompositionAsState import io.github.alexzhirkevich.compottie.rememberLottieComposition private const val lottieData = """ @@ -20,21 +26,21 @@ fun App() { contentAlignment = Alignment.Center ) { - val composition = rememberLottieComposition(lottieData) + val composition by rememberLottieComposition(lottieData) -// val progress = animateLottieCompositionAsState( -// cancellationBehavior = LottieCancellationBehavior.OnIterationFinish, -// composition = composition, -// repeatMode = RepeatMode.Restart, -// iterations = Int.MAX_VALUE -// ) + val progress = animateLottieCompositionAsState(composition) + println("LOTTIE DATA ${composition?.size}") - LottieAnimation( - composition = composition, -// progress = { progress.value }, - modifier = Modifier.size(300.dp) - ) + Row { + repeat(3) { + LottieAnimation( + composition = composition, + progress = { progress.value }, + modifier = Modifier.border(1.dp, Color.Blue) + ) + } + } } }