Android 实现Path曲线动画两种方案

Path动画是一种非常特殊的动画,可以理解为动画沿着Path路径移动。构建Path动画有两种方式,第一种是基于TypeEvalutor,该类用于控制View的状态、位置等。另一种是通过PathMeasure,这种可以更加直观的定义路径,同样也可以定义draw绘图等。

 

方案一:通过TypeEvalutor定义Path动画

曲线动画很常见,但最著名的是贝塞尔曲线动画(贝塞尔曲线的数学原理

class BezierEvaluator implements TypeEvaluator<PointF>{  
  
        @Override  
        public PointF evaluate(float fraction, PointF startValue,  
                PointF endValue) {  
            final float t = fraction;  
            float oneMinusT = 1.0f - t;  
            PointF point = new PointF();  
              
            PointF point0 = (PointF)startValue;  
              
            PointF point1 = new PointF();  
            point1.set(width, 0);  
              
            PointF point2 = new PointF();  
            point2.set(0, height);  
              
            PointF point3 = (PointF)endValue;  
              
            point.x = oneMinusT * oneMinusT * oneMinusT * (point0.x)   
                    + 3 * oneMinusT * oneMinusT * t * (point1.x)  
                    + 3 * oneMinusT * t * t * (point2.x)  
                    + t * t * t * (point3.x);  
              
            point.y = oneMinusT * oneMinusT * oneMinusT * (point0.y)   
                    + 3 * oneMinusT * oneMinusT * t * (point1.y)  
                    + 3 * oneMinusT * t * t * (point2.y)  
                    + t * t * t * (point3.y);             
            return point;  
        }     
    }  



valueAnimator.addUpdateListener(new AnimatorUpdateListener() {            
            @Override  
            public void onAnimationUpdate(ValueAnimator animation) {  
                PointF pointF = (PointF)animation.getAnimatedValue();  
                button.setX(pointF.x);  
                button.setY(pointF.y);  
            }  
        });  

 

方案二:PathMeasure动画

但是还有一类动画就是Path动画,通过PathMeasure实现Object在Path路径上动画

public class DynamicHeartView extends View {  
  
    private static final String TAG = "DynamicHeartView";  
    private static final int PATH_WIDTH = 2;  
    // 起始点  
    private static final int[] START_POINT = new int[] {  
            300, 270  
    };  
    // 爱心下端点  
    private static final int[] BOTTOM_POINT = new int[] {  
            300, 400  
    };  
    // 左侧控制点  
    private static final int[] LEFT_CONTROL_POINT = new int[] {  
            450, 200  
    };  
    // 右侧控制点  
    private static final int[] RIGHT_CONTROL_POINT = new int[] {  
            150, 200  
    };  
  
    private PathMeasure mPathMeasure;  
    private Paint mPaint;  
    private Path mPath;  
    private float[] mCurrentPosition = new float[2];  
  
    public DynamicHeartView(Context context) {  
        super(context);  
        init();  
    }  
  
    private void init() {  
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);  
        mPaint.setStyle(Style.STROKE);  
        mPaint.setStrokeWidth(PATH_WIDTH);  
        mPaint.setColor(Color.RED);  
  
        mPath = new Path();  
        mPath.moveTo(START_POINT[0], START_POINT[1]);  
        mPath.quadTo(RIGHT_CONTROL_POINT[0], RIGHT_CONTROL_POINT[1], BOTTOM_POINT[0],  
                BOTTOM_POINT[1]);  
        mPath.quadTo(LEFT_CONTROL_POINT[0], LEFT_CONTROL_POINT[1], START_POINT[0], START_POINT[1]);  
  
        mPathMeasure = new PathMeasure(mPath, true);  
        mCurrentPosition = new float[2];  
    }  
  
    @Override  
    protected void onDraw(Canvas canvas) {  
        super.onDraw(canvas);  
        canvas.drawColor(Color.WHITE);  
        canvas.drawPath(mPath, mPaint);  
  
        canvas.drawCircle(RIGHT_CONTROL_POINT[0], RIGHT_CONTROL_POINT[1], 5, mPaint);  
        canvas.drawCircle(LEFT_CONTROL_POINT[0], LEFT_CONTROL_POINT[1], 5, mPaint);  
  
        // 绘制对应目标  
        canvas.drawCircle(mCurrentPosition[0], mCurrentPosition[1], 10, mPaint);  
    }  
  
    // 开启路径动画  
    public void startPathAnim(long duration) {  
        // 0 - getLength()  
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, mPathMeasure.getLength());  
        Log.i(TAG, "measure length = " + mPathMeasure.getLength());  
        valueAnimator.setDuration(duration);  
        // 减速插值器  
        valueAnimator.setInterpolator(new DecelerateInterpolator());  
        valueAnimator.addUpdateListener(new AnimatorUpdateListener() {  
  
            @Override  
            public void onAnimationUpdate(ValueAnimator animation) {  
                float value = (Float) animation.getAnimatedValue();  
                // 获取当前点坐标封装到mCurrentPosition  
                mPathMeasure.getPosTan(value, mCurrentPosition, null);  
                postInvalidate();  
            }  
        });  
        valueAnimator.start();  
  
    }  
}  

http://blog.csdn.net/vrix/article/details/39206975

http://blog.csdn.net/tianjian4592/article/details/47067161

http://www.2cto.com/kf/201503/380377.html

http://blog.csdn.net/androidzhaoxiaogang/article/details/8680330

http://blog.csdn.net/linmiansheng/article/details/18763987

 

 

 

 

 

 

 

 

 

转载于:https://my.oschina.net/ososchina/blog/677307

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值