Skip to content
This repository has been archived by the owner on Oct 8, 2021. It is now read-only.

Commit

Permalink
Optimize the path morphing animation performance
Browse files Browse the repository at this point in the history
  • Loading branch information
tarek360 committed Jul 17, 2017
1 parent e10fb57 commit 276f4ad
Show file tree
Hide file tree
Showing 8 changed files with 549 additions and 528 deletions.
8 changes: 2 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ Animate any attribute in a specific path in the VectorDrawable

`fillColor`, `strokeColor`, `strokeAlpha`, `fillAlpha`, `size`, `width`, `height`, `scale`, `scaleX`, `scaleY`, `rotation`, `translationX`, `translationY`, `trimPathStart`, `trimPathEnd`, `trimPathOffset`.

- **Path morphing:**
- **Path morphing on API +11 :** 💪

<img src="/screenshots/animal_path_morphing.gif" width="250">

Expand Down Expand Up @@ -113,7 +113,7 @@ Add the following dependency to your module `build.gradle` file:
```gradle
dependencies {
...
compile 'com.github.tarek360.RichPath:animator:0.0.4'
compile 'com.github.tarek360.RichPath:animator:0.0.5'
}
```

Expand Down Expand Up @@ -147,10 +147,6 @@ RichPathAnimator
.start();
```

## TODO
- Optimize the path morphing animation performance.
- ...


## Credits

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.util.Log;
import android.view.animation.Interpolator;

import com.richpath.RichPath;
import com.richpath.pathparser.PathDataNode;
import com.richpath.pathparser.PathParserCompat;

import java.util.ArrayList;
import java.util.List;
Expand Down Expand Up @@ -175,9 +178,20 @@ private AnimationBuilder color(String propertyName, int... colors) {
}

public AnimationBuilder pathData(String... pathData) {

PathDataNode[][] pathDataNodes = new PathDataNode[pathData.length][];
for (int i = 0; i < pathData.length; i++) {
pathDataNodes[i] = PathParserCompat.createNodesFromPathData(pathData[i]);
}

if (!PathParserCompat.canMorph(pathDataNodes)) {
Log.w("RichPathAnimator", "the paths aren't compatible for morphing. The paths should have exact same length of commands, and exact same length of parameters for each command");
return this;
}

for (final RichPath path : paths) {
ObjectAnimator objectAnimator =
ObjectAnimator.ofObject(path, "pathData", new PathEvaluator(), pathData);
ObjectAnimator.ofObject(path, "pathDataNodes", new PathEvaluator(), pathDataNodes);
applyAnimatorProperties(objectAnimator, path);
}
return this;
Expand Down
57 changes: 15 additions & 42 deletions animator/src/main/java/com/richpathanimator/PathEvaluator.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,61 +2,34 @@

import android.animation.TypeEvaluator;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import com.richpath.pathparser.PathDataNode;
import com.richpath.pathparser.PathParserCompat;

/**
* Created by tarek on 7/14/17.
*/

public class PathEvaluator implements TypeEvaluator<String> {
public class PathEvaluator implements TypeEvaluator<PathDataNode[]> {

private String pathHolder;
private String startPath;
private String endPath;

private List<Float> startFloats = new ArrayList<>();
private List<Float> endFloats = new ArrayList<>();
private PathDataNode[] evaluatedNodes;

@Override
public String evaluate(float fraction, String startPath, String endPath) {


if (pathHolder == null
|| !this.startPath.equals(startPath) || !this.endPath.equals(endPath)) {

this.pathHolder = endPath;
this.startPath = startPath;
this.endPath = endPath;

startFloats.clear();
endFloats.clear();

Pattern p = Pattern.compile("[-]?[0-9]*\\.?[0-9]+");

Matcher startMatcher = p.matcher(startPath);
Matcher endMatcher = p.matcher(endPath);
public PathDataNode[] evaluate(float fraction, PathDataNode[] startPathDataNodes, PathDataNode[] endPathDataNodes) {

while (startMatcher.find() && endMatcher.find()) {
startFloats.add(Float.parseFloat(startMatcher.group()));
endFloats.add(Float.parseFloat(endMatcher.group()));
pathHolder = p.matcher(pathHolder).replaceFirst("#");
}
if (evaluatedNodes == null) {
evaluatedNodes = PathParserCompat.deepCopyNodes(startPathDataNodes);
}

String evaluatedPath = pathHolder;

for (int i = 0; i < startFloats.size(); i++) {

float startFloat = startFloats.get(i);
float value = startFloat + fraction * (endFloats.get(i) - startFloat);

evaluatedPath = evaluatedPath.replaceFirst("#", String.valueOf(value));
for (int i = 0; i < startPathDataNodes.length; i++) {
for (int j = 0; j < startPathDataNodes[i].getParams().length; j++) {
float startFloat = startPathDataNodes[i].getParams()[j];
float value = startFloat + fraction * (endPathDataNodes[i].getParams()[j] - startFloat);
evaluatedNodes[i].getParams()[j] = value;
}
}

return evaluatedPath;
return evaluatedNodes;
}


}
13 changes: 0 additions & 13 deletions app/src/main/res/drawable/square.xml

This file was deleted.

21 changes: 14 additions & 7 deletions richpath/src/main/java/com/richpath/RichPath.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@

import com.richpath.listener.OnRichPathUpdatedListener;
import com.richpath.model.Group;
import com.richpath.pathparser.PathDataNode;
import com.richpath.pathparser.PathParser;
import com.richpath.pathparser.PathParserCompat;
import com.richpath.util.PathUtils;
import com.richpath.util.XmlParser;

Expand Down Expand Up @@ -60,7 +62,7 @@ public class RichPath extends Path {

private Path originalPath;

private String pathData;
private PathDataNode[] pathDataNodes;
private List<Matrix> matrices;

public RichPath(String pathData) {
Expand Down Expand Up @@ -377,14 +379,17 @@ void scaleStrokeWidth(float scale) {
paint.setStrokeWidth(strokeWidth * scale);
}

public void setPathData(String pathData) {
setPathDataNodes(PathParserCompat.createNodesFromPathData(pathData));
}

public String getPathData() {
return pathData;
public PathDataNode[] getPathDataNodes() {
return pathDataNodes;
}

public void setPathData(String pathData) {
PathUtils.setPathData(this, pathData);
this.pathData = pathData;
public void setPathDataNodes(PathDataNode[] pathDataNodes) {
PathUtils.setPathDataNodes(this, pathDataNodes);
this.pathDataNodes = pathDataNodes;

for (Matrix matrix : matrices) {
transform(matrix);
Expand All @@ -395,7 +400,9 @@ public void setPathData(String pathData) {

public void inflate(Context context, XmlResourceParser xpp) {

pathData = XmlParser.getAttributeString(context, xpp, "pathData", name);
String pathData = XmlParser.getAttributeString(context, xpp, "pathData", name);

pathDataNodes = PathParserCompat.createNodesFromPathData(pathData);

name = XmlParser.getAttributeString(context, xpp, "name", name);

Expand Down
Loading

0 comments on commit 276f4ad

Please sign in to comment.