'How to animate a path on an Android Canvas
Is possible to attach an animator to a path?
Is there any other way to draw animated lines on the Canvas?
I searched this before I posted but I couldn’t find anything. In two other posts Draw a path as animation on Canvas in Android and How to draw a path on an Android Canvas with animation there are workaround solutions which does not work for me.
I post my code inside the onDraw method to specify what exactly I want.
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2);
paint.setColor(Color.BLACK);
Path path = new Path();
path.moveTo(10, 50); // THIS TRANSFORMATIONS TO BE ANIMATED!!!!!!!!
path.lineTo(40, 50);
path.moveTo(40, 50);
path.lineTo(50, 40);
// and so on...
canvas.drawPath(path, paint);
Solution 1:[1]
try this:
class PathDrawable extends Drawable implements AnimatorUpdateListener {
private Path mPath;
private Paint mPaint;
private ValueAnimator mAnimator;
public PathDrawable() {
mPath = new Path();
mPaint = new Paint();
mPaint.setColor(0xffffffff);
mPaint.setStrokeWidth(5);
mPaint.setStyle(Style.STROKE);
}
public void startAnimating() {
Rect b = getBounds();
mAnimator = ValueAnimator.ofInt(-b.bottom, b.bottom);
mAnimator.setDuration(1000);
mAnimator.addUpdateListener(this);
mAnimator.start();
}
@Override
public void draw(Canvas canvas) {
canvas.drawPath(mPath, mPaint);
}
@Override
public void setAlpha(int alpha) {
}
@Override
public void setColorFilter(ColorFilter cf) {
}
@Override
public int getOpacity() {
return PixelFormat.TRANSLUCENT;
}
@Override
public void onAnimationUpdate(ValueAnimator animator) {
mPath.reset();
Rect b = getBounds();
mPath.moveTo(b.left, b.bottom);
mPath.quadTo((b.right-b.left)/2, (Integer) animator.getAnimatedValue(), b.right, b.bottom);
invalidateSelf();
}
}
to test it add in your onCreate method:
TextView view = new TextView(this);
view.setText("click me");
view.setTextColor(0xffcccccc);
view.setGravity(Gravity.CENTER);
view.setTextSize(48);
final PathDrawable d = new PathDrawable();
view.setBackgroundDrawable(d);
OnClickListener l = new OnClickListener() {
@Override
public void onClick(View v) {
d.startAnimating();
}
};
view.setOnClickListener(l);
setContentView(view);
Solution 2:[2]
You can create a PathMeasure
for your path and determine the length of it:
private PathMeasure pathMeasure; // field
// After you've created your path
pathMeasure = new PathMeasure(path, false);
pathLength = pathMeasure.getLength();
You can then get get a specific point on the path using getPosTan() inside, say, a ValueAnimator's update listener:
final float[] position = new float[2]; // field
// Inside your animation's update method, where dt is your 0..1 animated fraction
final float distance = dt * pathLength;
pathMeasure.getPosTan(distance, position, null);
// If using onDraw you'll need to tell the view to redraw using the new position
invalidate();
You can then make use of the position in onDraw (or whatever).
canvas.drawCircle(position[0], position[1], radius, paint);
The advantages of this approach is that it is straightforward, doesn't require chunky maths, and works on all APIs.
If using API 21+, you can use a ValueAnimator and pass in a Path to use its positions, which is simpler. Example SO question.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | pskink |
Solution 2 | Community |