blob: e26008f2805232f10d906e5d20b63e99574aa4e6 [file] [log] [blame]
package com.airbnb.lottie.sample.compose.examples
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
import androidx.compose.material.Text
import androidx.compose.material.TextButton
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.rememberUpdatedState
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import com.airbnb.lottie.compose.rememberLottieAnimatable
import com.airbnb.lottie.compose.LottieAnimation
import com.airbnb.lottie.compose.LottieCancellationBehavior
import com.airbnb.lottie.compose.LottieClipSpec
import com.airbnb.lottie.compose.LottieCompositionSpec
import com.airbnb.lottie.compose.LottieConstants
import com.airbnb.lottie.compose.rememberLottieComposition
import com.airbnb.lottie.sample.compose.R
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.withContext
enum class TransitionSection {
Intro,
LoopMiddle,
Outro;
fun next(): TransitionSection = when (this) {
Intro -> LoopMiddle
LoopMiddle -> Outro
Outro -> Intro
}
}
@Composable
fun TransitionsExamplesPage() {
var state by remember { mutableStateOf(TransitionSection.Intro) }
UsageExamplePageScaffold { padding ->
Column(
modifier = Modifier
.padding(padding)
) {
Text(
"Single composition",
modifier = Modifier
.padding(8.dp)
)
SingleCompositionTransition(state)
Text(
"Multiple compositions",
modifier = Modifier
.padding(8.dp)
)
SplitCompositionTransition(state)
TextButton(
onClick = { state = state.next() }
) {
Text("State: $state")
}
}
}
}
@Composable
fun SingleCompositionTransition(section: TransitionSection) {
val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.bar))
val animatable = rememberLottieAnimatable()
val state by rememberUpdatedState(section)
LaunchedEffect(composition, animatable) {
composition ?: return@LaunchedEffect
snapshotFlow { state }.collectLatest { s ->
val clipSpec = when (s) {
TransitionSection.Intro -> LottieClipSpec.Progress(0f, 0.301f)
TransitionSection.LoopMiddle -> LottieClipSpec.Progress(0.301f, 2f / 3f)
TransitionSection.Outro -> LottieClipSpec.Progress(2f / 3f, 1f)
}
do {
animatable.animate(
composition,
clipSpec = clipSpec,
cancellationBehavior = LottieCancellationBehavior.OnIterationFinish,
)
} while (s == TransitionSection.LoopMiddle)
}
}
LottieAnimation(composition, animatable.progress)
}
@Composable
fun SplitCompositionTransition(section: TransitionSection) {
val introComposition = rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.bar_1))
val loopMiddleComposition = rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.bar_2))
val outroComposition = rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.bar_3))
val animatable = rememberLottieAnimatable()
LaunchedEffect(section) {
val composition = when (section) {
TransitionSection.Intro -> introComposition
TransitionSection.LoopMiddle -> loopMiddleComposition
TransitionSection.Outro -> outroComposition
}.await()
animatable.animate(
composition,
iterations = if (section == TransitionSection.LoopMiddle) LottieConstants.IterateForever else 1,
cancellationBehavior = LottieCancellationBehavior.OnIterationFinish,
)
}
LottieAnimation(animatable.composition, animatable.progress)
}