blob: 180b016b19f4f65f309e15596b87d0e9dbf5411a [file] [log] [blame]
package com.airbnb.lottie;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import java.util.ArrayList;
import java.util.List;
class EllipseShapeLayer extends AnimatableLayer {
EllipseShapeLayer(CircleShape circleShape, ShapeFill fill, ShapeStroke stroke,
ShapeTrimPath trim, Transform transform, Drawable.Callback callback) {
super(callback);
setBounds(transform.getBounds());
setAnchorPoint(transform.getAnchor().createAnimation());
setAlpha(transform.getOpacity().createAnimation());
setPosition(transform.getPosition().createAnimation());
setTransform(transform.getScale().createAnimation());
setRotation(transform.getRotation().createAnimation());
if (fill != null) {
CircleShapeLayer fillLayer = new CircleShapeLayer(getCallback());
fillLayer.setColor(fill.getColor().createAnimation());
fillLayer.setAlpha(fill.getOpacity().createAnimation());
fillLayer.updateCircle(
circleShape.getPosition().createAnimation(),
circleShape.getSize().createAnimation());
if (trim != null) {
fillLayer.setTrimPath(trim.getStart().createAnimation(), trim.getEnd().createAnimation(),
trim.getOffset().createAnimation());
}
addLayer(fillLayer);
}
if (stroke != null) {
CircleShapeLayer strokeLayer = new CircleShapeLayer(getCallback());
strokeLayer.setIsStroke();
strokeLayer.setColor(stroke.getColor().createAnimation());
strokeLayer.setAlpha(stroke.getOpacity().createAnimation());
strokeLayer.setLineWidth(stroke.getWidth().createAnimation());
if (!stroke.getLineDashPattern().isEmpty()) {
List<KeyframeAnimation<Float>> dashPatternAnimations =
new ArrayList<>(stroke.getLineDashPattern().size());
for (AnimatableFloatValue dashPattern : stroke.getLineDashPattern()) {
dashPatternAnimations.add(dashPattern.createAnimation());
}
strokeLayer.setDashPattern(dashPatternAnimations, stroke.getDashOffset().createAnimation());
}
strokeLayer.setLineCapType(stroke.getCapType());
strokeLayer.updateCircle(
circleShape.getPosition().createAnimation(),
circleShape.getSize().createAnimation());
if (trim != null) {
strokeLayer.setTrimPath(trim.getStart().createAnimation(), trim.getEnd().createAnimation(),
trim.getOffset().createAnimation());
}
addLayer(strokeLayer);
}
}
private static final class CircleShapeLayer extends ShapeLayer {
private static final float ELLIPSE_CONTROL_POINT_PERCENTAGE = 0.55228f;
private final KeyframeAnimation.AnimationListener<PointF> circleSizeChangedListener =
new KeyframeAnimation.AnimationListener<PointF>() {
@Override
public void onValueChanged(PointF progress) {
onCircleSizeChanged();
}
};
private final KeyframeAnimation.AnimationListener<PointF> circlePositionChangedListener =
new KeyframeAnimation.AnimationListener<PointF>() {
@Override
public void onValueChanged(PointF progress) {
invalidateSelf();
}
};
private final Path path = new Path();
private KeyframeAnimation<PointF> circleSize;
private KeyframeAnimation<PointF> circlePosition;
CircleShapeLayer(Drawable.Callback callback) {
super(callback);
setPath(new StaticKeyframeAnimation<>(path));
}
void updateCircle(KeyframeAnimation<PointF> circlePosition,
KeyframeAnimation<PointF> circleSize) {
if (this.circleSize != null) {
removeAnimation(this.circleSize);
this.circleSize.removeUpdateListener(circleSizeChangedListener);
}
if (this.circlePosition != null) {
removeAnimation(this.circlePosition);
this.circlePosition.removeUpdateListener(circlePositionChangedListener);
}
this.circleSize = circleSize;
this.circlePosition = circlePosition;
addAnimation(circleSize);
circleSize.addUpdateListener(circleSizeChangedListener);
addAnimation(circlePosition);
circlePosition.addUpdateListener(circlePositionChangedListener);
onCircleSizeChanged();
}
private void onCircleSizeChanged() {
float halfWidth = circleSize.getValue().x / 2f;
float halfHeight = circleSize.getValue().y / 2f;
setBounds(0, 0, (int) halfWidth * 2, (int) halfHeight * 2);
float cpW = halfWidth * ELLIPSE_CONTROL_POINT_PERCENTAGE;
float cpH = halfHeight * ELLIPSE_CONTROL_POINT_PERCENTAGE;
path.reset();
path.moveTo(0, -halfHeight);
path.cubicTo(0 + cpW, -halfHeight, halfWidth, 0 - cpH, halfWidth, 0);
path.cubicTo(halfWidth, 0 + cpH, 0 + cpW, halfHeight, 0, halfHeight);
path.cubicTo(0 - cpW, halfHeight, -halfWidth, 0 + cpH, -halfWidth, 0);
path.cubicTo(-halfWidth, 0 - cpH, 0 - cpW, -halfHeight, 0, -halfHeight);
path.offset(circlePosition.getValue().x, circlePosition.getValue().y);
onPathChanged();
invalidateSelf();
}
}
}