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 886747c3a..ed4b10c5e 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 @@ -59,6 +59,7 @@ import kotlin.math.roundToInt * @param alignment Define where the animation should be placed within this composable if it has a different * size than this composable. * @param contentScale Define how the animation should be scaled if it has a different size than this Composable. + * @param clipToComposition Determines whether or not Lottie will clip the animation to the original animation composition bounds. */ @Composable fun LottieAnimation( @@ -72,6 +73,7 @@ fun LottieAnimation( dynamicProperties: LottieDynamicProperties? = null, alignment: Alignment = Alignment.Center, contentScale: ContentScale = ContentScale.Fit, + clipToComposition: Boolean = true, ) { val drawable = remember { LottieDrawable() } val matrix = remember { Matrix() } @@ -106,6 +108,7 @@ fun LottieAnimation( drawable.isApplyingOpacityToLayersEnabled = applyOpacityToLayers drawable.enableMergePathsForKitKatAndAbove(enableMergePaths) drawable.useSoftwareRendering(useSoftwareRendering) + drawable.clipToCompositionBounds = clipToComposition drawable.progress = progress drawable.setBounds(0, 0, composition.bounds.width(), composition.bounds.height()) drawable.draw(canvas.nativeCanvas, matrix) @@ -136,6 +139,7 @@ fun LottieAnimation( dynamicProperties: LottieDynamicProperties? = null, alignment: Alignment = Alignment.Center, contentScale: ContentScale = ContentScale.Fit, + clipToComposition: Boolean = true, ) { val progress by animateLottieCompositionAsState( composition, @@ -156,6 +160,7 @@ fun LottieAnimation( dynamicProperties, alignment, contentScale, + clipToComposition, ) } diff --git a/lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java b/lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java index 908e2e52b..bd8e56097 100644 --- a/lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java +++ b/lottie/src/main/java/com/airbnb/lottie/LottieAnimationView.java @@ -184,6 +184,10 @@ private void init(@Nullable AttributeSet attrs, @AttrRes int defStyleAttr) { setSpeed(ta.getFloat(R.styleable.LottieAnimationView_lottie_speed, 1f)); } + if (ta.hasValue(R.styleable.LottieAnimationView_lottie_clipToCompositionBounds)) { + setClipToCompositionBounds(ta.getBoolean(R.styleable.LottieAnimationView_lottie_clipToCompositionBounds, true)); + } + setImageAssetsFolder(ta.getString(R.styleable.LottieAnimationView_lottie_imageAssetsFolder)); setProgress(ta.getFloat(R.styleable.LottieAnimationView_lottie_progress, 0)); enableMergePathsForKitKatAndAbove(ta.getBoolean( @@ -332,6 +336,26 @@ public boolean isMergePathsEnabledForKitKatAndAbove() { return lottieDrawable.isMergePathsEnabledForKitKatAndAbove(); } + /** + * Sets whether or not Lottie should clip to the original animation composition bounds. + * + * When set to true, the parent view may need to disable clipChildren so Lottie can render outside of the LottieAnimationView bounds. + * + * Defaults to true. + */ + public void setClipToCompositionBounds(boolean clipToCompositionBounds) { + lottieDrawable.setClipToCompositionBounds(clipToCompositionBounds); + } + + /** + * Gets whether or not Lottie should clip to the original animation composition bounds. + * + * Defaults to true. + */ + public boolean getClipToCompositionBounds() { + return lottieDrawable.getClipToCompositionBounds(); + } + /** * If set to true, all future compositions that are set will be cached so that they don't need to be parsed * next time they are loaded. This won't apply to compositions that have already been loaded. diff --git a/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java b/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java index ee9602f73..d801f8009 100644 --- a/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java +++ b/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java @@ -112,6 +112,7 @@ public void onAnimationUpdate(ValueAnimator animation) { @Nullable TextDelegate textDelegate; private boolean enableMergePaths; + private boolean clipToCompositionBounds = true; @Nullable private CompositionLayer compositionLayer; private int alpha = 255; @@ -208,6 +209,27 @@ public boolean isMergePathsEnabledForKitKatAndAbove() { return enableMergePaths; } + /** + * Sets whether or not Lottie should clip to the original animation composition bounds. + * + * Defaults to true. + */ + public void setClipToCompositionBounds(boolean clipToCompositionBounds) { + if (clipToCompositionBounds != this.clipToCompositionBounds) { + this.clipToCompositionBounds = clipToCompositionBounds; + invalidateSelf(); + } + } + + /** + * Gets whether or not Lottie should clip to the original animation composition bounds. + * + * Defaults to true. + */ + public boolean getClipToCompositionBounds() { + return clipToCompositionBounds; + } + /** * If you use image assets, you must explicitly specify the folder in assets/ in which they are * located because bodymovin uses the name filenames across all compositions (img_#). @@ -434,7 +456,6 @@ public void draw(@NonNull Canvas canvas) { } else { drawInternal(canvas); } - isDirty = false; L.endSection("Drawable#draw"); } @@ -445,6 +466,7 @@ private void drawInternal(@NonNull Canvas canvas) { } else { drawWithOriginalAspectRatio(canvas); } + isDirty = false; } private boolean boundsMatchesCompositionAspectRatio() { @@ -860,6 +882,7 @@ public int getRepeatCount() { } + @SuppressWarnings("unused") public boolean isLooping() { return animator.getRepeatCount() == ValueAnimator.INFINITE; } @@ -1221,7 +1244,10 @@ public void draw(Canvas canvas, Matrix matrix) { } if (softwareRenderingEnabled) { - renderAndDrawAsBitmap(canvas, compositionLayer, matrix); + canvas.save(); + canvas.concat(matrix); + renderAndDrawAsBitmap(canvas, compositionLayer); + canvas.restore(); } else { compositionLayer.draw(canvas, matrix, alpha); } @@ -1235,7 +1261,7 @@ private void drawWithNewAspectRatio(Canvas canvas) { } if (softwareRenderingEnabled) { - renderAndDrawAsBitmap(canvas, compositionLayer, null); + renderAndDrawAsBitmap(canvas, compositionLayer); } else { Rect bounds = getBounds(); // In fitXY mode, the scale doesn't take effect. @@ -1257,7 +1283,7 @@ private void drawWithOriginalAspectRatio(Canvas canvas) { } if (softwareRenderingEnabled) { - renderAndDrawAsBitmap(canvas, compositionLayer, null); + renderAndDrawAsBitmap(canvas, compositionLayer); } else { renderingMatrix.reset(); renderingMatrix.preScale(scale, scale); @@ -1272,23 +1298,38 @@ private void drawWithOriginalAspectRatio(Canvas canvas) { * @see LottieDrawable#useSoftwareRendering(boolean) * @see LottieAnimationView#setRenderMode(RenderMode) */ - private void renderAndDrawAsBitmap(Canvas originalCanvas, CompositionLayer compositionLayer, @Nullable Matrix parentMatrix) { + private void renderAndDrawAsBitmap(Canvas originalCanvas, CompositionLayer compositionLayer) { ensureSoftwareRenderingObjectsInitialized(); //noinspection deprecation originalCanvas.getMatrix(softwareRenderingOriginalCanvasMatrix); softwareRenderingOriginalCanvasMatrix.invert(softwareRenderingOriginalCanvasMatrixInverse); renderingMatrix.set(softwareRenderingOriginalCanvasMatrix); - if (parentMatrix != null) { - renderingMatrix.postConcat(parentMatrix); - } - // Determine what bounds the animation will render to after taking into account the canvas and parent matrix. - softwareRenderingTransformedBounds.set(0f, 0f, getIntrinsicWidth(), getIntrinsicHeight()); + // The bounds are usually intrinsicWidth x intrinsicHeight. If they are different, an external source is scaling this drawable. + // This is how ImageView.ScaleType.FIT_XY works. + Rect bounds = getBounds(); + float scaleX = bounds.width() / (float) getIntrinsicWidth(); + float scaleY = bounds.height() / (float) getIntrinsicHeight(); + + if (clipToCompositionBounds) { + // Only render the intrinsic (composition) bounds. + softwareRenderingTransformedBounds.set(0f, 0f, getIntrinsicWidth(), getIntrinsicHeight()); + } else { + // Find the full bounds of the animation. + softwareRenderingTransformedBounds.set(0f, 0f, 0f, 0f); + compositionLayer.getBounds(softwareRenderingTransformedBounds, null, false); + } + softwareRenderingTransformedBounds.set( + softwareRenderingTransformedBounds.left * scaleX, + softwareRenderingTransformedBounds.top * scaleY, + softwareRenderingTransformedBounds.right * scaleX, + softwareRenderingTransformedBounds.bottom * scaleY + ); + + // Transform the animation bounds to the bounds that they will render to on the canvas. renderingMatrix.mapRect(softwareRenderingTransformedBounds); - // We only need to render the portion of the animation that intersects with the canvas's bounds. - softwareRenderingTransformedBounds.intersect(0f, 0f, originalCanvas.getWidth(), originalCanvas.getHeight()); int renderWidth = (int) Math.ceil(softwareRenderingTransformedBounds.width()); int renderHeight = (int) Math.ceil(softwareRenderingTransformedBounds.height()); @@ -1303,10 +1344,7 @@ private void renderAndDrawAsBitmap(Canvas originalCanvas, CompositionLayer compo if (isDirty) { softwareRenderingBitmap.eraseColor(0); - renderingMatrix.preScale(scale, scale); - // The bounds are usually intrinsicWidth x intrinsicHeight. If they are different, an external source is scaling this drawable. - // This is how ImageView.ScaleType.FIT_XY works. - renderingMatrix.preScale(getBounds().width() / (float) getIntrinsicWidth(), getBounds().height() / (float) getIntrinsicHeight()); + renderingMatrix.preScale(scale * scaleX, scale * scaleY); // We want to render the smallest bitmap possible. If the animation doesn't start at the top left, we translate the canvas and shrink the // bitmap to avoid allocating and copying the empty space on the left and top. renderWidth and renderHeight take this into account. renderingMatrix.postTranslate(-softwareRenderingTransformedBounds.left, -softwareRenderingTransformedBounds.top); diff --git a/lottie/src/main/java/com/airbnb/lottie/model/layer/CompositionLayer.java b/lottie/src/main/java/com/airbnb/lottie/model/layer/CompositionLayer.java index c20ae753a..43ea6a18d 100644 --- a/lottie/src/main/java/com/airbnb/lottie/model/layer/CompositionLayer.java +++ b/lottie/src/main/java/com/airbnb/lottie/model/layer/CompositionLayer.java @@ -112,7 +112,7 @@ public CompositionLayer(LottieDrawable lottieDrawable, Layer layerModel, List= 0; i--) { boolean nonEmptyClip = true; - if (!newClipRect.isEmpty()) { + if (lottieDrawable.getClipToCompositionBounds() && !newClipRect.isEmpty()) { nonEmptyClip = canvas.clipRect(newClipRect); } if (nonEmptyClip) { diff --git a/lottie/src/main/res/values/attrs.xml b/lottie/src/main/res/values/attrs.xml index 1e8f30eed..73e34810d 100644 --- a/lottie/src/main/res/values/attrs.xml +++ b/lottie/src/main/res/values/attrs.xml @@ -28,5 +28,6 @@ + \ No newline at end of file diff --git a/snapshot-tests/src/androidTest/java/com/airbnb/lottie/snapshots/LottieSnapshotTest.kt b/snapshot-tests/src/androidTest/java/com/airbnb/lottie/snapshots/LottieSnapshotTest.kt index e758e1846..fec2593a7 100644 --- a/snapshot-tests/src/androidTest/java/com/airbnb/lottie/snapshots/LottieSnapshotTest.kt +++ b/snapshot-tests/src/androidTest/java/com/airbnb/lottie/snapshots/LottieSnapshotTest.kt @@ -17,6 +17,7 @@ import com.airbnb.lottie.snapshots.tests.ApplyOpacityToLayerTestCase import com.airbnb.lottie.snapshots.tests.AssetsTestCase import com.airbnb.lottie.snapshots.tests.ColorStateListColorFilterTestCase import com.airbnb.lottie.snapshots.tests.ComposeDynamicPropertiesTestCase +import com.airbnb.lottie.snapshots.tests.ComposeScaleTypesTestCase import com.airbnb.lottie.snapshots.tests.CustomBoundsTestCase import com.airbnb.lottie.snapshots.tests.DynamicPropertiesTestCase import com.airbnb.lottie.snapshots.tests.FailureTestCase @@ -110,6 +111,7 @@ class LottieSnapshotTest { FailureTestCase(), FrameBoundariesTestCase(), ScaleTypesTestCase(), + ComposeScaleTypesTestCase(), DynamicPropertiesTestCase(), MarkersTestCase(), AssetsTestCase(), diff --git a/snapshot-tests/src/androidTest/java/com/airbnb/lottie/snapshots/SnapshotTestCaseContext.kt b/snapshot-tests/src/androidTest/java/com/airbnb/lottie/snapshots/SnapshotTestCaseContext.kt index f254de1fd..b7e4e4be5 100644 --- a/snapshot-tests/src/androidTest/java/com/airbnb/lottie/snapshots/SnapshotTestCaseContext.kt +++ b/snapshot-tests/src/androidTest/java/com/airbnb/lottie/snapshots/SnapshotTestCaseContext.kt @@ -14,20 +14,18 @@ import android.widget.ImageView import android.widget.LinearLayout import androidx.compose.runtime.Composable import androidx.compose.ui.platform.ComposeView -import androidx.core.view.doOnAttach import androidx.core.view.doOnLayout -import androidx.core.view.doOnPreDraw import com.airbnb.lottie.FontAssetDelegate import com.airbnb.lottie.LottieAnimationView import com.airbnb.lottie.LottieComposition import com.airbnb.lottie.LottieCompositionFactory import com.airbnb.lottie.LottieDrawable +import com.airbnb.lottie.RenderMode import com.airbnb.lottie.model.LottieCompositionCache import com.airbnb.lottie.snapshots.utils.BitmapPool import com.airbnb.lottie.snapshots.utils.HappoSnapshotter import com.airbnb.lottie.snapshots.utils.ObjectPool import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.android.awaitFrame import kotlinx.coroutines.suspendCancellableCoroutine import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.withContext @@ -78,6 +76,7 @@ suspend fun SnapshotTestCaseContext.withAnimationView( snapshotVariant: String = "default", widthPx: Int = context.resources.displayMetrics.widthPixels, heightPx: Int = context.resources.displayMetrics.heightPixels, + renderHardwareAndSoftware: Boolean = false, callback: (LottieAnimationView) -> Unit, ) { val result = LottieCompositionFactory.fromAssetSync(context, assetName) @@ -101,10 +100,25 @@ suspend fun SnapshotTestCaseContext.withAnimationView( animationViewContainer.layout(0, 0, animationViewContainer.measuredWidth, animationViewContainer.measuredHeight) val bitmap = bitmapPool.acquire(animationView.width, animationView.height) val canvas = Canvas(bitmap) - log("Drawing $assetName") - animationView.draw(canvas) - animationViewPool.release(animationView) - snapshotter.record(bitmap, snapshotName, snapshotVariant) + if (renderHardwareAndSoftware) { + log("Drawing $assetName - hardware") + val renderMode = animationView.renderMode + animationView.renderMode = RenderMode.HARDWARE + animationView.draw(canvas) + snapshotter.record(bitmap, snapshotName, "$snapshotVariant - Hardware") + + bitmap.eraseColor(0) + animationView.renderMode = RenderMode.SOFTWARE + animationView.draw(canvas) + animationViewPool.release(animationView) + snapshotter.record(bitmap, snapshotName, "$snapshotVariant - Software") + animationView.renderMode = renderMode + } else { + log("Drawing $assetName") + animationView.draw(canvas) + animationViewPool.release(animationView) + snapshotter.record(bitmap, snapshotName, snapshotVariant) + } bitmapPool.release(bitmap) } @@ -153,23 +167,30 @@ suspend fun SnapshotTestCaseContext.snapshotComposition( bitmapPool.release(bitmap) } +fun SnapshotTestCaseContext.loadCompositionFromAssetsSync(fileName: String): LottieComposition { + return LottieCompositionFactory.fromAssetSync(context, fileName).value!! +} + suspend fun SnapshotTestCaseContext.snapshotComposable( name: String, variant: String = "default", - content: @Composable () -> Unit, + renderHardwareAndSoftware: Boolean = false, + content: @Composable (RenderMode) -> Unit, ) = withContext(Dispatchers.Default) { log("Snapshotting $name") val composeView = ComposeView(context) composeView.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT) - val bitmap = withContext(Dispatchers.Main) { - composeView.setContent(content) + var bitmap = withContext(Dispatchers.Main) { + composeView.setContent { + content(RenderMode.SOFTWARE) + } suspendCancellableCoroutine { cont -> composeView.doOnLayout { log("Drawing $name") - val bitmap = bitmapPool.acquire(composeView.width, composeView.height) - val canvas = Canvas(bitmap) + val b = bitmapPool.acquire(composeView.width, composeView.height) + val canvas = Canvas(b) composeView.draw(canvas) - cont.resume(bitmap) + cont.resume(b) } onActivity { activity -> activity.binding.content.addView(composeView) @@ -179,7 +200,33 @@ suspend fun SnapshotTestCaseContext.snapshotComposable( onActivity { activity -> activity.binding.content.removeView(composeView) } - LottieCompositionCache.getInstance().clear() - snapshotter.record(bitmap, name, variant) + snapshotter.record(bitmap, name, if (renderHardwareAndSoftware) "$variant - Software" else variant) bitmapPool.release(bitmap) + + if (renderHardwareAndSoftware) { + bitmap = withContext(Dispatchers.Main) { + composeView.setContent { + content(RenderMode.HARDWARE) + } + suspendCancellableCoroutine { cont -> + composeView.doOnLayout { + log("Drawing $name") + val b = bitmapPool.acquire(composeView.width, composeView.height) + val canvas = Canvas(b) + composeView.draw(canvas) + cont.resume(b) + } + onActivity { activity -> + activity.binding.content.addView(composeView) + } + } + } + onActivity { activity -> + activity.binding.content.removeView(composeView) + } + snapshotter.record(bitmap, name, "$variant - Hardware") + bitmapPool.release(bitmap) + } + + LottieCompositionCache.getInstance().clear() } \ No newline at end of file diff --git a/snapshot-tests/src/androidTest/java/com/airbnb/lottie/snapshots/tests/ComposeScaleTypesTestCase.kt b/snapshot-tests/src/androidTest/java/com/airbnb/lottie/snapshots/tests/ComposeScaleTypesTestCase.kt new file mode 100644 index 000000000..fa99b35a7 --- /dev/null +++ b/snapshot-tests/src/androidTest/java/com/airbnb/lottie/snapshots/tests/ComposeScaleTypesTestCase.kt @@ -0,0 +1,158 @@ +package com.airbnb.lottie.snapshots.tests + +import androidx.compose.foundation.layout.size +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.scale +import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.unit.dp +import com.airbnb.lottie.compose.LottieAnimation +import com.airbnb.lottie.snapshots.SnapshotTestCase +import com.airbnb.lottie.snapshots.SnapshotTestCaseContext +import com.airbnb.lottie.snapshots.loadCompositionFromAssetsSync +import com.airbnb.lottie.snapshots.snapshotComposable + +class ComposeScaleTypesTestCase : SnapshotTestCase { + override suspend fun SnapshotTestCaseContext.run() { + val composition = loadCompositionFromAssetsSync("Lottie Logo 1.json") + snapshotComposable("Compose Scale Types", "Wrap Content", renderHardwareAndSoftware = true) { renderMode -> + LottieAnimation( + composition, + 1f, + renderMode = renderMode, + ) + } + + snapshotComposable("Compose Scale Types", "720p", renderHardwareAndSoftware = true) { renderMode -> + LottieAnimation( + composition, + 1f, + renderMode = renderMode, + modifier = Modifier + .size(720.dp, 1280.dp) + ) + } + + snapshotComposable("Compose Scale Types", "300x300@2x", renderHardwareAndSoftware = true) { renderMode -> + LottieAnimation( + composition, + 1f, + renderMode = renderMode, + modifier = Modifier + .size(300.dp, 300.dp) + .scale(2f) + ) + } + + snapshotComposable("Compose Scale Types", "300x300@4x", renderHardwareAndSoftware = true) { renderMode -> + LottieAnimation( + composition, + 1f, + renderMode = renderMode, + modifier = Modifier + .size(300.dp, 300.dp) + .scale(4f) + ) + } + + snapshotComposable("Compose Scale Types", "300x300 Crop", renderHardwareAndSoftware = true) { renderMode -> + LottieAnimation( + composition, + 1f, + contentScale = ContentScale.Crop, + renderMode = renderMode, + modifier = Modifier + .size(300.dp, 300.dp) + ) + } + + snapshotComposable("Compose Scale Types", "300x300 Inside", renderHardwareAndSoftware = true) { renderMode -> + LottieAnimation( + composition, + 1f, + contentScale = ContentScale.Inside, + renderMode = renderMode, + modifier = Modifier + .size(300.dp, 300.dp) + ) + } + + snapshotComposable("Compose Scale Types", "300x300 FillBounds", renderHardwareAndSoftware = true) { renderMode -> + LottieAnimation( + composition, + 1f, + contentScale = ContentScale.FillBounds, + renderMode = renderMode, + modifier = Modifier + .size(300.dp, 300.dp) + ) + } + + snapshotComposable("Compose Scale Types", "300x300 Fit 2x", renderHardwareAndSoftware = true) { renderMode -> + LottieAnimation( + composition, + 1f, + contentScale = ContentScale.Fit, + renderMode = renderMode, + modifier = Modifier + .size(300.dp, 300.dp) + .scale(2f) + ) + } + + snapshotComposable("Compose Scale Types", "300x300 Crop 2x", renderHardwareAndSoftware = true) { renderMode -> + LottieAnimation( + composition, + 1f, + contentScale = ContentScale.Crop, + renderMode = renderMode, + modifier = Modifier + .size(300.dp, 300.dp) + .scale(2f) + ) + } + + snapshotComposable("Compose Scale Types", "600x600 Inside", renderHardwareAndSoftware = true) { renderMode -> + LottieAnimation( + composition, + 1f, + contentScale = ContentScale.Inside, + renderMode = renderMode, + modifier = Modifier + .size(600.dp, 600.dp) + ) + } + + snapshotComposable("Compose Scale Types", "600x600 FillBounds", renderHardwareAndSoftware = true) { renderMode -> + LottieAnimation( + composition, + 1f, + contentScale = ContentScale.FillBounds, + renderMode = renderMode, + modifier = Modifier + .size(600.dp, 600.dp) + ) + } + + snapshotComposable("Compose Scale Types", "600x600 Fit", renderHardwareAndSoftware = true) { renderMode -> + LottieAnimation( + composition, + 1f, + contentScale = ContentScale.Fit, + renderMode = renderMode, + modifier = Modifier + .size(600.dp, 600.dp) + ) + } + + snapshotComposable("Compose Scale Types", "300x600 FitBounds", renderHardwareAndSoftware = true) { renderMode -> + LottieAnimation( + composition, + 1f, + contentScale = ContentScale.FillBounds, + renderMode = renderMode, + modifier = Modifier + .size(300.dp, 600.dp) + ) + } + } +} \ No newline at end of file diff --git a/snapshot-tests/src/androidTest/java/com/airbnb/lottie/snapshots/tests/ScaleTypesTestCase.kt b/snapshot-tests/src/androidTest/java/com/airbnb/lottie/snapshots/tests/ScaleTypesTestCase.kt index 6cf274dd6..c012594c5 100644 --- a/snapshot-tests/src/androidTest/java/com/airbnb/lottie/snapshots/tests/ScaleTypesTestCase.kt +++ b/snapshot-tests/src/androidTest/java/com/airbnb/lottie/snapshots/tests/ScaleTypesTestCase.kt @@ -11,7 +11,7 @@ import com.airbnb.lottie.snapshots.withAnimationView class ScaleTypesTestCase : SnapshotTestCase { override suspend fun SnapshotTestCaseContext.run() { - withAnimationView("Lottie Logo 1.json", "Scale Types", "Wrap Content") { animationView -> + withAnimationView("Lottie Logo 1.json", "Scale Types", "Wrap Content", renderHardwareAndSoftware = true) { animationView -> animationView.progress = 1f animationView.updateLayoutParams { width = ViewGroup.LayoutParams.WRAP_CONTENT @@ -19,7 +19,7 @@ class ScaleTypesTestCase : SnapshotTestCase { } } - withAnimationView("Lottie Logo 1.json", "Scale Types", "Match Parent") { animationView -> + withAnimationView("Lottie Logo 1.json", "Scale Types", "Match Parent", renderHardwareAndSoftware = true) { animationView -> animationView.progress = 1f animationView.updateLayoutParams { width = ViewGroup.LayoutParams.MATCH_PARENT @@ -27,7 +27,7 @@ class ScaleTypesTestCase : SnapshotTestCase { } } - withAnimationView("Lottie Logo 1.json", "Scale Types", "300x300@2x") { animationView -> + withAnimationView("Lottie Logo 1.json", "Scale Types", "300x300@2x", renderHardwareAndSoftware = true) { animationView -> animationView.progress = 1f animationView.updateLayoutParams { width = 300.dp.toInt() @@ -36,7 +36,7 @@ class ScaleTypesTestCase : SnapshotTestCase { animationView.scale = 2f } - withAnimationView("Lottie Logo 1.json", "Scale Types", "300x300@4x") { animationView -> + withAnimationView("Lottie Logo 1.json", "Scale Types", "300x300@4x", renderHardwareAndSoftware = true) { animationView -> animationView.progress = 1f animationView.updateLayoutParams { width = 300.dp.toInt() @@ -45,7 +45,7 @@ class ScaleTypesTestCase : SnapshotTestCase { animationView.scale = 4f } - withAnimationView("Lottie Logo 1.json", "Scale Types", "300x300 centerCrop") { animationView -> + withAnimationView("Lottie Logo 1.json", "Scale Types", "300x300 centerCrop", renderHardwareAndSoftware = true) { animationView -> animationView.progress = 1f animationView.updateLayoutParams { width = 300.dp.toInt() @@ -54,7 +54,7 @@ class ScaleTypesTestCase : SnapshotTestCase { animationView.scaleType = ImageView.ScaleType.CENTER_CROP } - withAnimationView("Lottie Logo 1.json", "Scale Types", "300x300 centerInside") { animationView -> + withAnimationView("Lottie Logo 1.json", "Scale Types", "300x300 centerInside", renderHardwareAndSoftware = true) { animationView -> animationView.progress = 1f animationView.updateLayoutParams { width = 300.dp.toInt() @@ -63,7 +63,7 @@ class ScaleTypesTestCase : SnapshotTestCase { animationView.scaleType = ImageView.ScaleType.CENTER_INSIDE } - withAnimationView("Lottie Logo 1.json", "Scale Types", "300x300 fitXY") { animationView -> + withAnimationView("Lottie Logo 1.json", "Scale Types", "300x300 fitXY", renderHardwareAndSoftware = true) { animationView -> animationView.progress = 1f animationView.updateLayoutParams { width = 300.dp.toInt() @@ -72,17 +72,7 @@ class ScaleTypesTestCase : SnapshotTestCase { animationView.scaleType = ImageView.ScaleType.FIT_XY } - withAnimationView("Lottie Logo 1.json", "Scale Types", "300x300 fitXY DisableExtraScale") { animationView -> - animationView.progress = 1f - animationView.updateLayoutParams { - width = 300.dp.toInt() - height = 300.dp.toInt() - } - animationView.disableExtraScaleModeInFitXY() - animationView.scaleType = ImageView.ScaleType.FIT_XY - } - - withAnimationView("Lottie Logo 1.json", "Scale Types", "300x300 centerInside @2x") { animationView -> + withAnimationView("Lottie Logo 1.json", "Scale Types", "300x300 centerInside @2x", renderHardwareAndSoftware = true) { animationView -> animationView.progress = 1f animationView.updateLayoutParams { width = 300.dp.toInt() @@ -92,7 +82,7 @@ class ScaleTypesTestCase : SnapshotTestCase { animationView.scale = 2f } - withAnimationView("Lottie Logo 1.json", "Scale Types", "300x300 centerCrop @2x") { animationView -> + withAnimationView("Lottie Logo 1.json", "Scale Types", "300x300 centerCrop @2x", renderHardwareAndSoftware = true) { animationView -> animationView.progress = 1f animationView.updateLayoutParams { width = 300.dp.toInt() @@ -102,7 +92,7 @@ class ScaleTypesTestCase : SnapshotTestCase { animationView.scale = 2f } - withAnimationView("Lottie Logo 1.json", "Scale Types", "600x300 centerInside") { animationView -> + withAnimationView("Lottie Logo 1.json", "Scale Types", "600x300 centerInside", renderHardwareAndSoftware = true) { animationView -> animationView.progress = 1f animationView.updateLayoutParams { width = 600.dp.toInt() @@ -111,26 +101,16 @@ class ScaleTypesTestCase : SnapshotTestCase { animationView.scaleType = ImageView.ScaleType.CENTER_INSIDE } - withAnimationView("Lottie Logo 1.json", "Scale Types", "600x300 fitXY") { animationView -> - animationView.progress = 1f - animationView.updateLayoutParams { - width = 600.dp.toInt() - height = 300.dp.toInt() - } - animationView.scaleType = ImageView.ScaleType.FIT_XY - } - - withAnimationView("Lottie Logo 1.json", "Scale Types", "600x300 fitXY DisableExtraScale") { animationView -> + withAnimationView("Lottie Logo 1.json", "Scale Types", "600x300 fitXY", renderHardwareAndSoftware = true) { animationView -> animationView.progress = 1f animationView.updateLayoutParams { width = 600.dp.toInt() height = 300.dp.toInt() } - animationView.disableExtraScaleModeInFitXY() animationView.scaleType = ImageView.ScaleType.FIT_XY } - withAnimationView("Lottie Logo 1.json", "Scale Types", "300x600 centerInside") { animationView -> + withAnimationView("Lottie Logo 1.json", "Scale Types", "300x600 centerInside", renderHardwareAndSoftware = true) { animationView -> animationView.progress = 1f animationView.updateLayoutParams { width = 300.dp.toInt() @@ -139,22 +119,12 @@ class ScaleTypesTestCase : SnapshotTestCase { animationView.scaleType = ImageView.ScaleType.CENTER_INSIDE } - withAnimationView("Lottie Logo 1.json", "Scale Types", "300x600 fitXY") { animationView -> - animationView.progress = 1f - animationView.updateLayoutParams { - width = 300.dp.toInt() - height = 600.dp.toInt() - } - animationView.scaleType = ImageView.ScaleType.FIT_XY - } - - withAnimationView("Lottie Logo 1.json", "Scale Types", "300x600 fitXY DisableExtraScale") { animationView -> + withAnimationView("Lottie Logo 1.json", "Scale Types", "300x600 fitXY", renderHardwareAndSoftware = true) { animationView -> animationView.progress = 1f animationView.updateLayoutParams { width = 300.dp.toInt() height = 600.dp.toInt() } - animationView.disableExtraScaleModeInFitXY() animationView.scaleType = ImageView.ScaleType.FIT_XY } }