blob: a16c04c77cb5f04c069e363806a0671d31c336f1 [file] [log] [blame]
package com.airbnb.lottie;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Path;
import android.support.annotation.Nullable;
import android.util.Log;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
class ContentGroup implements DrawingContent, PathContent,
BaseKeyframeAnimation.AnimationListener {
private static final String TAG = ContentGroup.class.getSimpleName();
private final Matrix matrix = new Matrix();
private final Path path = new Path();
private final List<Content> contents = new ArrayList<>();
private final LottieDrawable lottieDrawable;
@Nullable private List<PathContent> pathContents;
@Nullable private TransformKeyframeAnimation transformAnimation;
ContentGroup(final LottieDrawable lottieDrawable, BaseLayer layer, ShapeGroup shapeGroup) {
this.lottieDrawable = lottieDrawable;
List<Object> items = shapeGroup.getItems();
if (items.isEmpty()) {
return;
}
Object potentialTransform = items.get(items.size() - 1);
if (potentialTransform instanceof AnimatableTransform) {
transformAnimation = ((AnimatableTransform) potentialTransform).createAnimation();
//noinspection ConstantConditions
transformAnimation.addAnimationsToLayer(layer);
transformAnimation.addListener(this);
}
for (int i = 0; i < items.size(); i++) {
Object item = items.get(i);
if (item instanceof ShapeFill) {
contents.add(new FillContent(lottieDrawable, layer, (ShapeFill) item));
} else if (item instanceof GradientFill) {
contents.add(new GradientFillContent(lottieDrawable, layer, (GradientFill) item));
} else if (item instanceof ShapeStroke) {
contents.add(new StrokeContent(lottieDrawable, layer, (ShapeStroke) item));
} else if (item instanceof ShapeGroup) {
contents.add(new ContentGroup(lottieDrawable, layer, (ShapeGroup) item));
} else if (item instanceof RectangleShape) {
contents.add(new RectangleContent(lottieDrawable, layer, (RectangleShape) item));
} else if (item instanceof CircleShape) {
contents.add(new EllipseContent(lottieDrawable, layer, (CircleShape) item));
} else if (item instanceof ShapePath) {
contents.add(new ShapeContent(lottieDrawable, layer, (ShapePath) item));
} else if (item instanceof PolystarShape) {
contents.add(new PolystarContent(lottieDrawable, layer, (PolystarShape) item));
} else if (item instanceof ShapeTrimPath) {
contents.add(new TrimPathContent(layer, (ShapeTrimPath) item));
} else //noinspection StatementWithEmptyBody
if (item instanceof MergePaths) {
if (lottieDrawable.enableMergePathsForKitKatAndAbove()) {
contents.add(new MergePathsContent((MergePaths) item));
} else {
Log.w(TAG, "Animation contains merge paths but they are disabled.");
}
}
}
List<Content> contentsToRemove = new ArrayList<>();
MergePathsContent currentMergePathsContent = null;
for (int i = contents.size() - 1; i >= 0; i--) {
Content content = contents.get(i);
if (content instanceof MergePathsContent) {
currentMergePathsContent = (MergePathsContent) content;
}
if (currentMergePathsContent != null && content != currentMergePathsContent) {
currentMergePathsContent.addContentIfNeeded(content);
contentsToRemove.add(content);
}
}
Iterator<Content> it = contents.iterator();
while (it.hasNext()) {
Content content = it.next();
if (contentsToRemove.contains(content)) {
it.remove();
}
}
}
@Override public void onValueChanged() {
lottieDrawable.invalidateSelf();
}
@Override public void setContents(List<Content> contentsBefore, List<Content> contentsAfter) {
// Do nothing with contents after.
List<Content> myContentsBefore = new ArrayList<>(contentsBefore.size() + contents.size());
myContentsBefore.addAll(contentsBefore);
for (int i = contents.size() - 1; i >= 0; i--) {
Content content = contents.get(i);
content.setContents(myContentsBefore, contents.subList(0, i));
myContentsBefore.add(content);
}
}
List<PathContent> getPathList() {
if (pathContents == null) {
pathContents = new ArrayList<>();
for (int i = 0; i < contents.size(); i++) {
Content content = contents.get(i);
if (content instanceof PathContent) {
pathContents.add((PathContent) content);
}
}
}
return pathContents;
}
Matrix getTransformationMatrix() {
if (transformAnimation != null) {
return transformAnimation.getMatrix();
}
matrix.reset();
return matrix;
}
@Override public Path getPath() {
// TODO: cache this somehow.
matrix.reset();
if (transformAnimation != null) {
matrix.set(transformAnimation.getMatrix());
}
path.reset();
for (int i = contents.size() - 1; i >= 0; i--) {
Content content = contents.get(i);
if (content instanceof PathContent) {
path.addPath(((PathContent) content).getPath(), matrix);
}
}
return path;
}
@Override public void draw(Canvas canvas, Matrix parentMatrix, int parentAlpha) {
matrix.set(parentMatrix);
int alpha;
if (transformAnimation != null) {
matrix.preConcat(transformAnimation.getMatrix());
alpha =
(int) ((transformAnimation.getOpacity().getValue() / 100f * parentAlpha / 255f) * 255);
} else {
alpha = parentAlpha;
}
for (int i = contents.size() - 1; i >= 0; i--) {
Object content = contents.get(i);
if (content instanceof DrawingContent) {
((DrawingContent) content).draw(canvas, matrix, alpha);
}
}
}
}