【问题标题】:How to animate a path on an Android Canvas如何在画布上为路径设置动画 - android
【发布时间】:2013-09-08 02:09:46
【问题描述】:

可以将动画师附加到路径吗?有没有其他方法可以在画布上绘制动画线条?我在发布之前搜索了这个,但没有任何关于这个。在另外两个帖子 herehere 中,有一些解决方案不适合我。

我在 onDraw 方法中发布我的代码来指定我到底想要什么。

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);

有什么想法吗???

【问题讨论】:

    标签: android animation canvas path


    【解决方案1】:

    您可以按时间变换画布,即:

    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);
        }
    
    }
    

    【讨论】:

    • 圆呢?我的意思是,我怎样才能绘制弧形或椭圆形动画?
    • 进行了 2 处更改。 1:添加了无效(); 2. matrix.postRotate(30.0f);行 matrix.postRotate(30 * elapsedTime/1000);会导致你的动画太快。
    • 如果您想要精确计时的动画,帧速率方法并不是一个好主意 - 但它非常适合小效果。
    • @slott 说得好,但你是如何制作更精确的动画的?
    • 对于更复杂的动画,我会使用纹理视图来确保最佳绘制性能。然后你可以有一个完美的线程运行时间并指导主渲染线程。
    【解决方案2】:

    试试这个:

    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();
        }
    }
    

    在你的 onCreate 方法中添加测试它:

    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);
    

    【讨论】:

    • 立即画线,没有动画
    • 代码工作..但我想设置任何颜色的圆形背景以及你提到的笔画。有什么想法吗?
    • 这应该是公认的答案......可以调整以影响所有平局......喜欢; mAnimator = ValueAnimator.ofInt(0.0f, 1.0f);然后您可以将所有值乘以动画 val
    • 您能详细说明一下吗?我的意思是您是否进行了基准测试并发现这个比公认的答案更有利,或者您只是尝试了这个并且它对您有用,这就是为什么您认为这应该是答案?
    • @FARID 因为 ObjectAnimator 用于任何动画并且 ObjectAnimator 扩展了 ValueAnimator 所以使用其中之一
    【解决方案3】:

    您可以为您的路径创建一个PathMeasure 并确定它的长度:

    private PathMeasure pathMeasure; // field
    
    // After you've created your path
    pathMeasure = new PathMeasure(path, false); 
    pathLength = pathMeasure.getLength();
    

    然后,您可以使用 getPosTan() 获取路径上的特定点,例如 ValueAnimator 的更新侦听器:

    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(); 
    

    然后您可以使用 onDraw(或其他)中的位置。

    canvas.drawCircle(position[0], position[1], radius, paint);
    

    这种方法的优点是简单明了,不需要繁琐的数学运算,并且适用于所有 API。

    如果使用 API 21+,你可以使用 ValueAnimator 并传入一个 Path 来使用它的位置,这样更简单。 Example SO question.

    【讨论】:

      猜你喜欢
      • 2011-06-06
      • 1970-01-01
      • 2020-11-02
      • 1970-01-01
      • 1970-01-01
      • 2012-03-27
      • 2012-08-15
      相关资源
      最近更新 更多