Skip to content

Commit

Permalink
[Compose] Add merge paths flag (#1744)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jossiwolf authored Feb 24, 2021
1 parent 67f3af1 commit 4b69bc1
Show file tree
Hide file tree
Showing 8 changed files with 77 additions and 21 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG_COMPOSE.md
Original file line number Diff line number Diff line change
@@ -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

Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ buildscript {
}
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'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import androidx.compose.ui.geometry.Offset
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
Expand Down Expand Up @@ -80,11 +79,7 @@ fun LottieAnimation(
state: LottieAnimationState,
modifier: Modifier = Modifier,
) {
val drawable = remember {
LottieDrawable().apply {
enableMergePathsForKitKatAndAbove(true)
}
}
val drawable = remember { LottieDrawable() }

SideEffect {
drawable.composition = composition
Expand Down Expand Up @@ -118,7 +113,6 @@ fun LottieAnimation(
}

if (composition == null || composition.duration == 0f) return
SideEffect {}

Canvas(
modifier = Modifier
Expand All @@ -129,6 +123,7 @@ fun LottieAnimation(
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)
}) {
Expand All @@ -143,4 +138,4 @@ private fun Modifier.maintainAspectRatio(composition: LottieComposition?): Modif
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)
Original file line number Diff line number Diff line change
Expand Up @@ -6,33 +6,63 @@ import androidx.compose.runtime.mutableStateOf
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)

// TODO: make this public
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)
Expand All @@ -58,6 +88,18 @@ class LottieAnimationState(
*/
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
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,8 @@ fun LottieFilesSearchPage(
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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ import androidx.compose.ui.Alignment
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
Expand Down Expand Up @@ -50,6 +52,7 @@ fun PlayerPage(
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) }
Expand All @@ -72,6 +75,7 @@ fun PlayerPage(

animationState.outlineMasksAndMattes = outlineMasksAndMattes.value
animationState.applyOpacityToLayers = applyOpacityToLayers.value
animationState.enableMergePaths = enableMergePaths.value

Scaffold(
scaffoldState = scaffoldState,
Expand Down Expand Up @@ -164,6 +168,7 @@ fun PlayerPage(
backgroundColor = backgroundColorToolbar,
outlineMasksAndMattes = outlineMasksAndMattes,
applyOpacityToLayers = applyOpacityToLayers,
enableMergePaths = enableMergePaths
)
}
}
Expand Down Expand Up @@ -344,6 +349,7 @@ private fun Toolbar(
backgroundColor: MutableState<Boolean>,
outlineMasksAndMattes: MutableState<Boolean>,
applyOpacityToLayers: MutableState<Boolean>,
enableMergePaths: MutableState<Boolean>,
) {
Row(
modifier = Modifier
Expand All @@ -352,40 +358,47 @@ private fun Toolbar(
.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)
)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import androidx.compose.ui.Alignment
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
Expand All @@ -28,7 +29,7 @@ fun ToolbarChip(
isActivated: Boolean,
onClick: (isActivated: Boolean) -> Unit,
modifier: Modifier = Modifier,
@DrawableRes iconRes: Int = 0,
iconPainter: Painter? = null,
) {
val unActivatedColor = remember { Color(0xFF444444) }
Surface(
Expand All @@ -44,9 +45,9 @@ fun ToolbarChip(
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),
Expand All @@ -67,7 +68,7 @@ fun ToolbarChip(
@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 = {}
Expand Down
1 change: 1 addition & 0 deletions sample-compose/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down

0 comments on commit 4b69bc1

Please sign in to comment.