| package com.airbnb.lottie.parser; |
| |
| import android.graphics.PointF; |
| import android.util.JsonToken; |
| import com.airbnb.lottie.LottieComposition; |
| import com.airbnb.lottie.model.animatable.AnimatableFloatValue; |
| import com.airbnb.lottie.model.animatable.AnimatableIntegerValue; |
| import com.airbnb.lottie.model.animatable.AnimatablePathValue; |
| import com.airbnb.lottie.model.animatable.AnimatableScaleValue; |
| import com.airbnb.lottie.model.animatable.AnimatableSplitDimensionPathValue; |
| import com.airbnb.lottie.model.animatable.AnimatableTransform; |
| import com.airbnb.lottie.model.animatable.AnimatableValue; |
| import com.airbnb.lottie.parser.moshi.JsonReader; |
| import com.airbnb.lottie.value.Keyframe; |
| |
| import java.io.IOException; |
| |
| public class AnimatableTransformParser { |
| |
| private AnimatableTransformParser() { |
| } |
| |
| |
| private static JsonReader.Options NAMES = JsonReader.Options.of( |
| "a", |
| "p", |
| "s", |
| "rz", |
| "r", |
| "o", |
| "so", |
| "eo", |
| "sk", |
| "sa" |
| ); |
| private static JsonReader.Options ANIMATABLE_NAMES = JsonReader.Options.of("k"); |
| |
| public static AnimatableTransform parse( |
| JsonReader reader, LottieComposition composition) throws IOException { |
| AnimatablePathValue anchorPoint = null; |
| AnimatableValue<PointF, PointF> position = null; |
| AnimatableScaleValue scale = null; |
| AnimatableFloatValue rotation = null; |
| AnimatableIntegerValue opacity = null; |
| AnimatableFloatValue startOpacity = null; |
| AnimatableFloatValue endOpacity = null; |
| AnimatableFloatValue skew = null; |
| AnimatableFloatValue skewAngle = null; |
| |
| boolean isObject = reader.peek() == JsonReader.Token.BEGIN_OBJECT; |
| if (isObject) { |
| reader.beginObject(); |
| } |
| while (reader.hasNext()) { |
| switch (reader.selectName(NAMES)) { |
| case 0: |
| reader.beginObject(); |
| while (reader.hasNext()) { |
| switch (reader.selectName(ANIMATABLE_NAMES)) { |
| case 0: |
| anchorPoint = AnimatablePathValueParser.parse(reader, composition); |
| break; |
| default: |
| reader.skipName(); |
| reader.skipValue(); |
| } |
| } |
| reader.endObject(); |
| break; |
| case 1: |
| position = |
| AnimatablePathValueParser.parseSplitPath(reader, composition); |
| break; |
| case 2: |
| scale = AnimatableValueParser.parseScale(reader, composition); |
| break; |
| case 3: |
| composition.addWarning("Lottie doesn't support 3D layers."); |
| case 4: |
| /** |
| * Sometimes split path rotation gets exported like: |
| * "rz": { |
| * "a": 1, |
| * "k": [ |
| * {} |
| * ] |
| * }, |
| * which doesn't parse to a real keyframe. |
| */ |
| rotation = AnimatableValueParser.parseFloat(reader, composition, false); |
| if (rotation.getKeyframes().isEmpty()) { |
| rotation.getKeyframes().add(new Keyframe(composition, 0f, 0f, null, 0f, composition.getEndFrame())); |
| } else if (rotation.getKeyframes().get(0).startValue == null) { |
| rotation.getKeyframes().set(0, new Keyframe(composition, 0f, 0f, null, 0f, composition.getEndFrame())); |
| } |
| break; |
| case 5: |
| opacity = AnimatableValueParser.parseInteger(reader, composition); |
| break; |
| case 6: |
| startOpacity = AnimatableValueParser.parseFloat(reader, composition, false); |
| break; |
| case 7: |
| endOpacity = AnimatableValueParser.parseFloat(reader, composition, false); |
| break; |
| case 8: |
| skew = AnimatableValueParser.parseFloat(reader, composition, false); |
| break; |
| case 9: |
| skewAngle = AnimatableValueParser.parseFloat(reader, composition, false); |
| break; |
| default: |
| reader.skipName(); |
| reader.skipValue(); |
| } |
| } |
| if (isObject) { |
| reader.endObject(); |
| } |
| |
| if (isAnchorPointIdentity(anchorPoint)) { |
| anchorPoint = null; |
| } |
| if (isPositionIdentity(position)) { |
| position = null; |
| } |
| if (isRotationIdentity(rotation)) { |
| rotation = null; |
| } |
| if (isScaleIdentity(scale)) { |
| scale = null; |
| } |
| if (isSkewIdentity(skew)) { |
| skew = null; |
| } |
| if (isSkewAngleIdentity(skewAngle)) { |
| skewAngle = null; |
| } |
| return new AnimatableTransform(anchorPoint, position, scale, rotation, opacity, startOpacity, endOpacity, skew, skewAngle); |
| } |
| |
| private static boolean isAnchorPointIdentity(AnimatablePathValue anchorPoint) { |
| return anchorPoint == null || (anchorPoint.isStatic() && anchorPoint.getKeyframes().get(0).startValue.equals(0f, 0f)); |
| } |
| |
| private static boolean isPositionIdentity(AnimatableValue<PointF, PointF> position) { |
| return position == null || ( |
| !(position instanceof AnimatableSplitDimensionPathValue) && |
| position.isStatic() && position.getKeyframes().get(0).startValue.equals(0f, 0f)); |
| } |
| |
| private static boolean isRotationIdentity(AnimatableFloatValue rotation) { |
| return rotation == null || (rotation.isStatic() && rotation.getKeyframes().get(0).startValue == 0f); |
| } |
| |
| private static boolean isScaleIdentity(AnimatableScaleValue scale) { |
| return scale == null || (scale.isStatic() && scale.getKeyframes().get(0).startValue.equals(1f, 1f)); |
| } |
| |
| private static boolean isSkewIdentity(AnimatableFloatValue skew) { |
| return skew == null || (skew.isStatic() && skew.getKeyframes().get(0).startValue == 0f); |
| } |
| |
| private static boolean isSkewAngleIdentity(AnimatableFloatValue skewAngle) { |
| return skewAngle == null || (skewAngle.isStatic() && skewAngle.getKeyframes().get(0).startValue == 0f); |
| } |
| } |