[Compose] Add merge paths flag (#1744)
Fixes #1734
LottieAnimationView had merge paths disabled by default, but LottieAnimation enables them by default. As long as merge paths contain known bugs, I think it makes sense not to change that behavior - what do you think?
I added a flag for it to the state. If you want, we can add it as a constructor param too, but I feel like that's not needed as it's not that commonly used.
diff --git a/CHANGELOG_COMPOSE.md b/CHANGELOG_COMPOSE.md
index 0e00617..9056077 100644
--- a/CHANGELOG_COMPOSE.md
+++ b/CHANGELOG_COMPOSE.md
@@ -1,6 +1,9 @@
#### Note: For the time being, we won't provide numbered releases for every new Jetpack Compose
version. Check out our [snapshot builds](https://github.com/airbnb/lottie/blob/master/android-compose.md#getting-started) instead.
+# 1.0.0-alpha07-SNAPSHOT
+* Add flag for merge paths to LottieAnimationState
+
# 1.0.0-alpha06
* Compatible with Jetpack Compose Alpha 12
diff --git a/build.gradle b/build.gradle
index a180923..b35e692 100644
--- a/build.gradle
+++ b/build.gradle
@@ -16,7 +16,7 @@
}
dependencies {
classpath 'org.ajoberstar:grgit:1.9.3'
- classpath 'com.android.tools.build:gradle:7.0.0-alpha06'
+ classpath 'com.android.tools.build:gradle:7.0.0-alpha07'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
classpath "org.jetbrains.kotlin:kotlin-android-extensions:$kotlinVersion"
classpath 'org.ajoberstar:grgit:1.9.3'
diff --git a/lottie-compose/src/main/java/com/airbnb/lottie/compose/LottieAnimation.kt b/lottie-compose/src/main/java/com/airbnb/lottie/compose/LottieAnimation.kt
index 1c7a10a..61b3473 100644
--- a/lottie-compose/src/main/java/com/airbnb/lottie/compose/LottieAnimation.kt
+++ b/lottie-compose/src/main/java/com/airbnb/lottie/compose/LottieAnimation.kt
@@ -9,7 +9,6 @@
import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
import androidx.compose.ui.graphics.drawscope.withTransform
import androidx.compose.ui.graphics.nativeCanvas
-import androidx.compose.ui.platform.AmbientContext
import androidx.compose.ui.platform.LocalContext
import com.airbnb.lottie.LottieComposition
import com.airbnb.lottie.LottieCompositionFactory
@@ -80,11 +79,7 @@
state: LottieAnimationState,
modifier: Modifier = Modifier,
) {
- val drawable = remember {
- LottieDrawable().apply {
- enableMergePathsForKitKatAndAbove(true)
- }
- }
+ val drawable = remember { LottieDrawable() }
SideEffect {
drawable.composition = composition
@@ -118,7 +113,6 @@
}
if (composition == null || composition.duration == 0f) return
- SideEffect {}
Canvas(
modifier = Modifier
@@ -129,6 +123,7 @@
drawable.progress = state.progress
drawable.setOutlineMasksAndMattes(state.outlineMasksAndMattes)
drawable.isApplyingOpacityToLayersEnabled = state.applyOpacityToLayers
+ drawable.enableMergePathsForKitKatAndAbove(state.enableMergePaths)
withTransform({
scale(size.width / composition.bounds.width().toFloat(), size.height / composition.bounds.height().toFloat(), Offset.Zero)
}) {
@@ -143,4 +138,4 @@
return this.then(aspectRatio(composition.bounds.width() / composition.bounds.height().toFloat()))
}
-private fun lerp(a: Float, b: Float, @FloatRange(from = 0.0, to = 1.0) percentage: Float) = a + percentage * (b - a)
+private fun lerp(a: Float, b: Float, @FloatRange(from = 0.0, to = 1.0) percentage: Float) = a + percentage * (b - a)
diff --git a/lottie-compose/src/main/java/com/airbnb/lottie/compose/LottieAnimationState.kt b/lottie-compose/src/main/java/com/airbnb/lottie/compose/LottieAnimationState.kt
index a245789..b410285 100644
--- a/lottie-compose/src/main/java/com/airbnb/lottie/compose/LottieAnimationState.kt
+++ b/lottie-compose/src/main/java/com/airbnb/lottie/compose/LottieAnimationState.kt
@@ -6,25 +6,47 @@
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
+/**
+ * Create a [LottieAnimationState] and remember it
+ *
+ * @param autoPlay Initial value for [LottieAnimationState.isPlaying]
+ * @param repeatCount Initial value for [LottieAnimationState.repeatCount]
+ * @param initialProgress Initial value for [LottieAnimationState.progress]
+ * @param enableMergePaths Initial value for [LottieAnimationState.enableMergePaths]
+ */
@Composable
fun rememberLottieAnimationState(
autoPlay: Boolean = true,
repeatCount: Int = 0,
initialProgress: Float = 0f,
+ enableMergePaths: Boolean = true
): LottieAnimationState {
// Use rememberSavedInstanceState so you can pause/resume animations
return remember(repeatCount, autoPlay) {
- LottieAnimationState(isPlaying = autoPlay, repeatCount, initialProgress)
+ LottieAnimationState(
+ isPlaying = autoPlay,
+ repeatCount = repeatCount,
+ initialProgress = initialProgress,
+ enableMergePaths = enableMergePaths
+ )
}
}
/**
- * @see rememberLottieAnimationState()
+ * State of the [LottieAnimation] composable
+ *
+ * @param isPlaying Initial value for [isPlaying]
+ * @param repeatCount Initial value for [repeatCount]
+ * @param initialProgress Initial value for [progress]
+ * @param enableMergePaths Initial value for [enableMergePaths]
+ *
+ * @see rememberLottieAnimationState
*/
class LottieAnimationState(
isPlaying: Boolean,
repeatCount: Int = 0,
initialProgress: Float = 0f,
+ enableMergePaths: Boolean = true
) {
var progress by mutableStateOf(initialProgress)
@@ -32,7 +54,15 @@
private var _frame = mutableStateOf(0)
val frame: Int by _frame
+ /**
+ * Whether the animation is currently playing.
+ */
var isPlaying by mutableStateOf(isPlaying)
+
+ /**
+ * How many times the animation will be played. Use [Int.MAX_VALUE] for
+ * infinite repetitions.
+ */
var repeatCount by mutableStateOf(repeatCount)
var speed by mutableStateOf(1f)
@@ -58,6 +88,18 @@
*/
var applyOpacityToLayers by mutableStateOf(false)
+ /**
+ * Enable this to get merge path support.
+ * <p>
+ * Merge paths currently don't work if the the operand shape is entirely contained within the
+ * first shape. If you need to cut out one shape from another shape, use an even-odd fill type
+ * instead of using merge paths.
+ * <p>
+ * If your animation contains merge paths and you are encountering rendering issues, disabling
+ * merge paths might help.
+ */
+ var enableMergePaths by mutableStateOf(enableMergePaths)
+
internal fun updateFrame(frame: Int) {
_frame.value = frame
}
diff --git a/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/lottiefiles/LottieFilesSearchPage.kt b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/lottiefiles/LottieFilesSearchPage.kt
index 37e48e2..4933326 100644
--- a/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/lottiefiles/LottieFilesSearchPage.kt
+++ b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/lottiefiles/LottieFilesSearchPage.kt
@@ -141,7 +141,8 @@
value = state.query,
onValueChange = onQueryChanged,
label = { Text(stringResource(R.string.query)) },
- modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp)
+ modifier = Modifier.fillMaxWidth().padding(horizontal = 16.dp),
+ singleLine = true
)
LazyColumn(
modifier = Modifier.weight(1f)
diff --git a/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/player/PlayerPage.kt b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/player/PlayerPage.kt
index a8c81f4..f882c01 100644
--- a/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/player/PlayerPage.kt
+++ b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/player/PlayerPage.kt
@@ -19,7 +19,9 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.vector.rememberVectorPainter
import androidx.compose.ui.res.colorResource
+import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextAlign
@@ -50,6 +52,7 @@
val scaffoldState = rememberScaffoldState()
val outlineMasksAndMattes = remember { mutableStateOf(false) }
val applyOpacityToLayers = remember { mutableStateOf(false) }
+ val enableMergePaths = remember { mutableStateOf(animationState.enableMergePaths) }
var focusMode by remember { mutableStateOf(false) }
var backgroundColor by remember { mutableStateOf(animationBackgroundColor) }
var showWarningsDialog by remember { mutableStateOf(false) }
@@ -72,6 +75,7 @@
animationState.outlineMasksAndMattes = outlineMasksAndMattes.value
animationState.applyOpacityToLayers = applyOpacityToLayers.value
+ animationState.enableMergePaths = enableMergePaths.value
Scaffold(
scaffoldState = scaffoldState,
@@ -164,6 +168,7 @@
backgroundColor = backgroundColorToolbar,
outlineMasksAndMattes = outlineMasksAndMattes,
applyOpacityToLayers = applyOpacityToLayers,
+ enableMergePaths = enableMergePaths
)
}
}
@@ -344,6 +349,7 @@
backgroundColor: MutableState<Boolean>,
outlineMasksAndMattes: MutableState<Boolean>,
applyOpacityToLayers: MutableState<Boolean>,
+ enableMergePaths: MutableState<Boolean>,
) {
Row(
modifier = Modifier
@@ -352,40 +358,47 @@
.padding(bottom = 8.dp)
) {
ToolbarChip(
- iconRes = R.drawable.ic_masks_and_mattes,
+ iconPainter = painterResource(R.drawable.ic_masks_and_mattes),
label = stringResource(R.string.toolbar_item_masks),
isActivated = outlineMasksAndMattes.value,
onClick = { outlineMasksAndMattes.value = it },
modifier = Modifier.padding(end = 8.dp)
)
ToolbarChip(
- iconRes = R.drawable.ic_layers,
+ iconPainter = painterResource(R.drawable.ic_layers),
label = stringResource(R.string.toolbar_item_opacity_layers),
isActivated = applyOpacityToLayers.value,
onClick = { applyOpacityToLayers.value = it },
modifier = Modifier.padding(end = 8.dp)
)
ToolbarChip(
- iconRes = R.drawable.ic_color,
+ iconPainter = painterResource(R.drawable.ic_color),
label = stringResource(R.string.toolbar_item_color),
isActivated = backgroundColor.value,
onClick = { backgroundColor.value = it },
modifier = Modifier.padding(end = 8.dp)
)
ToolbarChip(
- iconRes = R.drawable.ic_speed,
+ iconPainter = painterResource(R.drawable.ic_speed),
label = stringResource(R.string.toolbar_item_speed),
isActivated = speed.value,
onClick = { speed.value = it },
modifier = Modifier.padding(end = 8.dp)
)
ToolbarChip(
- iconRes = R.drawable.ic_border,
+ iconPainter = painterResource(R.drawable.ic_border),
label = stringResource(R.string.toolbar_item_border),
isActivated = border.value,
onClick = { border.value = it },
modifier = Modifier.padding(end = 8.dp)
)
+ ToolbarChip(
+ iconPainter = rememberVectorPainter(Icons.Default.MergeType),
+ label = stringResource(R.string.toolbar_item_merge_paths),
+ isActivated = enableMergePaths.value,
+ onClick = { enableMergePaths.value = it },
+ modifier = Modifier.padding(end = 8.dp)
+ )
}
}
diff --git a/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/player/ToolbarChip.kt b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/player/ToolbarChip.kt
index 69904b8..1440c32 100644
--- a/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/player/ToolbarChip.kt
+++ b/sample-compose/src/main/java/com/airbnb/lottie/sample/compose/player/ToolbarChip.kt
@@ -13,6 +13,7 @@
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
@@ -28,7 +29,7 @@
isActivated: Boolean,
onClick: (isActivated: Boolean) -> Unit,
modifier: Modifier = Modifier,
- @DrawableRes iconRes: Int = 0,
+ iconPainter: Painter? = null,
) {
val unActivatedColor = remember { Color(0xFF444444) }
Surface(
@@ -44,9 +45,9 @@
modifier = Modifier
.padding(horizontal = 8.dp, vertical = 4.dp)
) {
- if (iconRes != 0) {
+ if (iconPainter != null) {
Icon(
- painterResource(iconRes),
+ iconPainter,
tint = if (isActivated) Color.White else unActivatedColor,
modifier = Modifier
.preferredSize(12.dp),
@@ -67,7 +68,7 @@
@Composable
fun PreviewToolbarChip() {
ToolbarChip(
- iconRes = R.drawable.ic_border,
+ iconPainter = painterResource(R.drawable.ic_border),
label = stringResource(R.string.toolbar_item_border),
isActivated = false,
onClick = {}
diff --git a/sample-compose/src/main/res/values/strings.xml b/sample-compose/src/main/res/values/strings.xml
index 46de9bf..4f9ee0d 100644
--- a/sample-compose/src/main/res/values/strings.xml
+++ b/sample-compose/src/main/res/values/strings.xml
@@ -22,6 +22,7 @@
<string name="toolbar_item_speed">Speed</string>
<string name="toolbar_item_color">Background</string>
<string name="toolbar_item_opacity_layers">Apply Opacity To Layers</string>
+ <string name="toolbar_item_merge_paths">Enable Merge Paths</string>
<string name="failed_to_load">Failed to load composition</string>
<string name="ok">OK</string>