仿支付宝支付成功打勾动画(关于PathMeasure你该知道的东西)

来源:互联网 发布:grub启动linux 编辑:程序博客网 时间:2024/05/21 00:11

Android路径动画

沿预定路径生成动画图像(无论是直线或曲线)是做动画时一种常见的情况。传统方法是寻找Path的函数(贝塞尔函数用的比较多),带入x的值来计算y的值, 然后使用坐标(x,y)来完成动画。
现在还有一种更简单的方法:通过使用path和PathMeasure来完成。
Path大家都很熟悉了,那PathMeasure是什么东西呢,从命名上就可以看出,这相当于Path坐标计算器。以前我们需要知道路径函数的算法才能算坐标,现在PathMeasure帮我们处理了这一过程。现在来讲讲它的使用方法

初始化

PathMeasure pathMeasure = new PathMeasure();

PathMeasure提供了一个setPath()将path和pathMeasure进行绑定

pathMeasure.setPath(path,false);

当然也可通过初始化的时候就指定:

PathMeasure pathMeasure= new PathMeasure(Path path,boolean forceClosed);

forceClosed决定是否强制闭合,设置为true的话,path首位最尾在measure时会闭合。

forceClosed参数对绑定的Path不会产生任何影响,例如一个折线段的Path,本身是没有闭合的,forceClosed设置为True的时候,PathMeasure计算的Path是闭合的,但Path本身绘制出来是不会闭合的。

forceClosed参数对PathMeasure的测量结果有影响,还是例如前面说的一个折线段的Path,本身没有闭合,forceClosed设置为True,PathMeasure的计算就会包含最后一段闭合的路径,与原来的Path不同。

API提供的其它重要方法

  • float getLength():获取路径长度
  • boolean getPosTan(float distance, float[] pos, float[] tan) 传入一个大于0小于getLength()的获取坐标点和切线的坐标,放入post[]和tan[]中
  • boolean getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo) 传入一个开始点和结束点, 然后会返回介于这之间的Path,当作dst。startWithMoveTo通常为True,保证每次截取的Path片段都是正常的、完整的
  • boolean nextContour 当需要传入多个path的时候进行切换用的,contour时是轮廓的意思

支付动画简单版——打勾动画

PathMeasure到底是怎么做的呢,我们先以一个支付动画的简单版来说明,在这个实例中,要完成的操作就是画一个圆,在圆圈里面进行动态打勾。这里用的的是getSegment不断绘制path的每一段,直到绘制完成。
怎么控制进度呢,我们定义了一个tickPercent来标记进度的百分比,通过valueAnimator来实时更新进度来绘制,具体的实现代码如下:

public class CircleTickView extends View {    private PathMeasure tickPathMeasure;    /**     * 打钩百分比     */    float tickPercent = 0;    private Path path;    //初始化打钩路径    private Path tickPath;    // 圆圈的大小,半径    private int circleRadius;    private int circleColor;    private int circleStrokeWidth;    private RectF rec;    private Paint tickPaint;    public CircleTickView(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        init(context, attrs);    }    public CircleTickView(Context context, AttributeSet attrs) {        super(context, attrs);        init(context, attrs);    }    public CircleTickView(Context context) {        super(context);        init(context, null);    }    public void init(Context context, AttributeSet attrs) {        TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleTickView);        circleRadius = mTypedArray.getInteger(R.styleable.CircleTickView_circleRadius, 150);        circleColor = mTypedArray.getColor(R.styleable.CircleTickView_circleViewColor, ContextCompat.getColor(context, R.color.colorPrimary));        circleStrokeWidth = mTypedArray.getInteger(R.styleable.CircleTickView_circleStrokeWidth, 20);        mTypedArray.recycle();        tickPaint = new Paint();        tickPathMeasure = new PathMeasure();        rec = new RectF();        path = new Path();        tickPath = new Path();        tickPaint.setStyle(Paint.Style.STROKE);        tickPaint.setAntiAlias(true);        tickPaint.setColor(circleColor);        tickPaint.setStrokeWidth(circleStrokeWidth);        //打钩动画        ValueAnimator mTickAnimation;        mTickAnimation = ValueAnimator.ofFloat(0f, 1f);        mTickAnimation.setStartDelay(1000);        mTickAnimation.setDuration(500);        mTickAnimation.setInterpolator(new AccelerateInterpolator());        mTickAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {            @Override            public void onAnimationUpdate(ValueAnimator animation) {                tickPercent = (float) animation.getAnimatedValue();                invalidate();            }        });        mTickAnimation.start();    }    @Override    protected void onDraw(Canvas canvas) {        int width = canvas.getWidth();        int height = canvas.getHeight();        // 根据设置该view的高度,进行对所画图进行居中处理        int offsetHeight = (height - circleRadius * 2) / 2;        // 设置第一条直线的相关参数        int firStartX = width / 2 - circleRadius * 3 / 5;        int firStartY = offsetHeight + circleRadius;        int firEndX = (width / 2 - circleRadius / 5) - 1;        int firEndY = offsetHeight + circleRadius + circleRadius / 2 + 1;        int secEndX = width / 2 + circleRadius * 3 / 5;        int secEndY = offsetHeight + circleRadius / 2;        rec.set(width / 2 - circleRadius, offsetHeight, width / 2 + circleRadius, offsetHeight + circleRadius * 2);        tickPath.moveTo(firStartX, firStartY);        tickPath.lineTo(firEndX, firEndY);        tickPath.lineTo(secEndX, secEndY);        tickPathMeasure.setPath(tickPath, false);        /*         * On KITKAT and earlier releases, the resulting path may not display on a hardware-accelerated Canvas.         * A simple workaround is to add a single operation to this path, such as dst.rLineTo(0, 0).         */        tickPathMeasure.getSegment(0, tickPercent * tickPathMeasure.getLength(), path, true);        path.rLineTo(0, 0);        canvas.drawPath(path, tickPaint);        canvas.drawArc(rec, 0, 360, false, tickPaint);    }}

想写这么多了,有空再把全真的支付宝支付动画po上来。

0 0