diff --git a/LottieSample/src/androidTest/java/com/airbnb/lottie/samples/LottieTest.kt b/LottieSample/src/androidTest/java/com/airbnb/lottie/samples/LottieTest.kt index 123c20f178..973b21e467 100644 --- a/LottieSample/src/androidTest/java/com/airbnb/lottie/samples/LottieTest.kt +++ b/LottieSample/src/androidTest/java/com/airbnb/lottie/samples/LottieTest.kt @@ -728,6 +728,14 @@ class LottieTest { drawable.addValueCallback(KeyPath("Linear", "Rectangle", "Gradient Fill"), LottieProperty.OPACITY, value) } + withDrawable("Tests/MatteTimeStretchScan.json", "Mirror animation", "Mirror animation") { + drawable -> + drawable.addValueCallback(KeyPath.COMPOSITION, LottieProperty.TRANSFORM_ANCHOR_POINT, + { PointF(drawable.bounds.width().toFloat(), 0f) }) + drawable.addValueCallback(KeyPath.COMPOSITION, LottieProperty.TRANSFORM_SCALE, + { ScaleXY(-1.0f, 1.0f) }) + } + withDrawable("Tests/Text.json", "Text", "Text Fill (Blue -> Green)") { drawable -> val value = object : LottieValueCallback() { override fun getValue(frameInfo: LottieFrameInfo?) = Color.GREEN diff --git a/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java b/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java index 70fa4afbcc..1969ec68c7 100644 --- a/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java +++ b/lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java @@ -972,7 +972,10 @@ public void run(LottieComposition composition) { return; } boolean invalidate; - if (keyPath.getResolvedElement() != null) { + if (keyPath == KeyPath.COMPOSITION) { + compositionLayer.addValueCallback(property, callback); + invalidate = true; + } else if (keyPath.getResolvedElement() != null) { keyPath.getResolvedElement().addValueCallback(property, callback); invalidate = true; } else { diff --git a/lottie/src/main/java/com/airbnb/lottie/model/KeyPath.java b/lottie/src/main/java/com/airbnb/lottie/model/KeyPath.java index 31a50cf28f..64fe09f10f 100644 --- a/lottie/src/main/java/com/airbnb/lottie/model/KeyPath.java +++ b/lottie/src/main/java/com/airbnb/lottie/model/KeyPath.java @@ -11,7 +11,8 @@ /** * Defines which content to target. * The keypath can contain wildcards ('*') with match exactly 1 item. - * or globstars ('**') which match 0 or more items. + * or globstars ('**') which match 0 or more items. or KeyPath.COMPOSITION + * to represent the root composition layer. * * For example, if your content were arranged like this: * Gabriel (Shape Layer) @@ -35,12 +36,19 @@ * new KeyPath("*", "Body", Left Hand", "Fill"); * Match anything with the name Fill: * new KeyPath("**", "Fill"); + * Target the the root composition layer: + * KeyPath.COMPOSITION * * * NOTE: Content that are part of merge paths or repeaters cannot currently be resolved with * a {@link KeyPath}. This may be fixed in the future. */ public class KeyPath { + /** + * A singleton KeyPath that targets on the root composition layer. + * This is useful if you want to apply transformer to the animation as a whole. + */ + public final static KeyPath COMPOSITION = new KeyPath("COMPOSITION"); private final List keys; @Nullable private KeyPathElement resolvedElement;