How to animate a path on canvas - android

前端 未结 3 1268
醉酒成梦
醉酒成梦 2020-11-28 05:19

Is possible to attach an animator to a path? Is there any other way to draw on canvas animated lines? I searched this before i post , but there is nothing about this. In two

相关标签:
3条回答
  • 2020-11-28 05:26

    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);
    
    0 讨论(0)
  • 2020-11-28 05:27

    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.

    0 讨论(0)
  • 2020-11-28 05:48

    You can transform your canvas by time, i.e:

    class MyView extends View {
    
        int framesPerSecond = 60;
        long animationDuration = 10000; // 10 seconds
    
        Matrix matrix = new Matrix(); // transformation matrix
    
        Path path = new Path();       // your path
        Paint paint = new Paint();    // your paint
    
        long startTime;
    
        public MyView(Context context) {
            super(context);
    
            // start the animation:
            this.startTime = System.currentTimeMillis();
            this.postInvalidate(); 
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
    
            long elapsedTime = System.currentTimeMillis() - startTime;
    
            matrix.postRotate(30 * elapsedTime/1000);        // rotate 30° every second
            matrix.postTranslate(100 * elapsedTime/1000, 0); // move 100 pixels to the right
            // other transformations...
    
            canvas.concat(matrix);        // call this before drawing on the canvas!!
    
            canvas.drawPath(path, paint); // draw on canvas
    
            if(elapsedTime < animationDuration)
                this.postInvalidateDelayed( 1000 / framesPerSecond);
        }
    
    }
    
    0 讨论(0)
提交回复
热议问题