Skip to content

Commit 66bc2fb

Browse files
pranayairanPranay Airan
andauthored
[a11y] Adding reduce motion logic to LottieAnimation for compose usage (#2542)
Our changes in #2536 didn't work for `LottieAnimation` in compose. While LottieAnimation does use LottieDrawable, it has it's own animator and draws on canvas directly. This PR addresses that issue by making some logic of reduce motion readable outside LottieDrawable and consuming that logic in `LottieAnimation` I tested this by adding a sample lottie file with reduce motion marker locally, see the attached video. https://github.com/user-attachments/assets/eb33333f-86b8-46fa-9bbb-82bff8a8c7fe Co-authored-by: Pranay Airan <[email protected]>
1 parent a1fb304 commit 66bc2fb

File tree

2 files changed

+16
-8
lines changed

2 files changed

+16
-8
lines changed

lottie-compose/src/main/java/com/airbnb/lottie/compose/LottieAnimation.kt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
1717
import androidx.compose.ui.graphics.nativeCanvas
1818
import androidx.compose.ui.layout.ContentScale
1919
import androidx.compose.ui.layout.ScaleFactor
20+
import androidx.compose.ui.platform.LocalContext
2021
import androidx.compose.ui.unit.IntSize
2122
import com.airbnb.lottie.AsyncUpdates
2223
import com.airbnb.lottie.LottieComposition
@@ -101,6 +102,7 @@ fun LottieAnimation(
101102
if (composition == null || composition.duration == 0f) return Box(modifier)
102103

103104
val bounds = composition.bounds
105+
val context = LocalContext.current
104106
Canvas(
105107
modifier = modifier
106108
.lottieSize(bounds.width(), bounds.height())
@@ -131,7 +133,12 @@ fun LottieAnimation(
131133
drawable.maintainOriginalImageBounds = maintainOriginalImageBounds
132134
drawable.clipToCompositionBounds = clipToCompositionBounds
133135
drawable.clipTextToBoundingBox = clipTextToBoundingBox
134-
drawable.progress = progress()
136+
val markerForAnimationsDisabled = drawable.markerForAnimationsDisabled
137+
if (!drawable.animationsEnabled(context) && markerForAnimationsDisabled != null) {
138+
drawable.progress = markerForAnimationsDisabled.startFrame
139+
} else {
140+
drawable.progress = progress()
141+
}
135142
drawable.setBounds(0, 0, bounds.width(), bounds.height())
136143
drawable.draw(canvas.nativeCanvas, matrix)
137144
}

lottie/src/main/java/com/airbnb/lottie/LottieDrawable.java

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -823,15 +823,15 @@ public void playAnimation() {
823823
}
824824

825825
computeRenderMode();
826-
if (animationsEnabled() || getRepeatCount() == 0) {
826+
if (animationsEnabled(getContext()) || getRepeatCount() == 0) {
827827
if (isVisible()) {
828828
animator.playAnimation();
829829
onVisibleAction = OnVisibleAction.NONE;
830830
} else {
831831
onVisibleAction = OnVisibleAction.PLAY;
832832
}
833833
}
834-
if (!animationsEnabled()) {
834+
if (!animationsEnabled(getContext())) {
835835
Marker markerForAnimationsDisabled = getMarkerForAnimationsDisabled();
836836
if (markerForAnimationsDisabled != null) {
837837
setFrame((int) markerForAnimationsDisabled.startFrame);
@@ -853,7 +853,8 @@ public void playAnimation() {
853853
*
854854
* @return The first non-null marker from the list of allowed reduced motion markers, or null if no such marker is found.
855855
*/
856-
private Marker getMarkerForAnimationsDisabled() {
856+
@RestrictTo(RestrictTo.Scope.LIBRARY)
857+
public Marker getMarkerForAnimationsDisabled() {
857858
Marker marker = null;
858859
for (String markerName : ALLOWED_REDUCED_MOTION_MARKERS) {
859860
marker = composition.getMarker(markerName);
@@ -885,15 +886,15 @@ public void resumeAnimation() {
885886
}
886887

887888
computeRenderMode();
888-
if (animationsEnabled() || getRepeatCount() == 0) {
889+
if (animationsEnabled(getContext()) || getRepeatCount() == 0) {
889890
if (isVisible()) {
890891
animator.resumeAnimation();
891892
onVisibleAction = OnVisibleAction.NONE;
892893
} else {
893894
onVisibleAction = OnVisibleAction.RESUME;
894895
}
895896
}
896-
if (!animationsEnabled()) {
897+
if (!animationsEnabled(getContext())) {
897898
setFrame((int) (getSpeed() < 0 ? getMinFrame() : getMaxFrame()));
898899
animator.endAnimation();
899900
if (!isVisible()) {
@@ -1244,12 +1245,12 @@ boolean isAnimatingOrWillAnimateOnVisible() {
12441245
}
12451246
}
12461247

1247-
private boolean animationsEnabled() {
1248+
public boolean animationsEnabled(Context context) {
12481249
if (ignoreSystemAnimationsDisabled) {
12491250
return true;
12501251
}
12511252
return systemAnimationsEnabled &&
1252-
L.getReducedMotionOption().getCurrentReducedMotionMode(getContext()) == ReducedMotionMode.STANDARD_MOTION;
1253+
L.getReducedMotionOption().getCurrentReducedMotionMode(context) == ReducedMotionMode.STANDARD_MOTION;
12531254
}
12541255

12551256
/**

0 commit comments

Comments
 (0)