【Android开源项目解析】仿支付宝付款成功及"天女散花"效果实现——看PathMeasure大展身手

话说,在前面两篇文章中,我们学习了BitmapShader、Path的基本使用,那么这一篇文章,咱们接着来学习一下PathMeasure的用法。什么,你没听说过PathMeasure?那你就要OUT咯~

项目效果图

废话不多说,在开始讲解之前,先看下最终实现的效果。

效果一:

仿支付宝支付成功效果

效果二:

这两个项目都是使用Path和PathMeature配合完成的,由其他项目改造而来

项目一是七叔写的,我对代码进行了大量改造。

项目二是不小心搜到的,然后进行了改造,原文请戳这里

本文代码请到这里下载

PathMeasure介绍

PathMeasure这个类确实是不太常见的,关于这个类的介绍也是甚少,那么这个类是用来干嘛的呢?主要其实是配合Path,来计算Path里面点的坐标的,或者是给一个范围,来截取Path其中的一部分的。

这么说,你肯定也迷糊,咱们先简单看一下有哪些方法,然后根据案例来进行讲解更好一些。

构造方法有两个,很好理解,不多解释。

PathMeasure()
PathMeasure(Path path, boolean forceClosed)

重点看下常用方法:

  • float getLength() 返回当前contour(解释为轮廓不太恰当,我觉得更像是笔画)的长度,也就是这一个Path有多长
  • boolean getPosTan(float distance, float[] pos, float[] tan) 传入一个距离distance(0<=distance<=getLength()),然后会计算当前距离的坐标点和切线,注意,pos会自动填充上坐标,这个方法很重要
  • boolean getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo) 传入一个开始和结束距离,然后会返回介于这之间的Path,在这里就是dst,他会被填充上内容,这个方法很重要
  • boolean nextContour() 移动到下一个笔画,如果你的Path是由多个笔画组成的话,那么就可以使用这个方法
  • void setPath(Path path, boolean forceClosed)这个方法也比较重要,用来设置新的Path对象的,算是对第一个构造函数的一个补充

仿支付宝实现原理解析

下面,我将介绍一下如何实现下面的这个效果

首先分析需求:

  • 需要有三种状态:加载中,成功,失败
  • 加载中时,需要不断更换颜色
  • 加载中状态时,圆弧要不断的变换长度和位置
  • 成功状态和失败状态,需要把√和×一笔一划的画出来

OK,基本就是这些需求,那么对应着需求,咱们看一下解决方案

  • 有三种状态好说,用静态常量或者是枚举类型进行区分
  • 不断变换颜色也好说,只要改变Paint的颜色就可以啦
  • 不断的变化长度和位置,从效果图上可以看出来,我们需要画一段圆弧,那就要用下面的drawArc(),需要知道范围,起始角度和绘制角度,由于需要不断的变化长度,因此就需要用Animator,具体实现一会详谈
Canvas.drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,Paint paint) 
  • 需要画出来形状,其实就是一些线段,那么就需要用Path了,但是如何能一笔一划的效果呢?那就要靠PathMeasure啦

下面开始讲解代码实现,最好参照着源代码看下面的文章。

首先看怎么用ConfirmView呢?很简单,只需要调用animatedWithState()然后传入一个枚举类型即可

confirmView.animatedWithState(ConfirmView.State.Progressing);

这个枚举类型在类的内部,代表三种状态

public enum State {
        Success, Fail, Progressing
    }

再看构造函数,很简单,只是进行了变量的初始化,这些变量的具体作用,我将在下面用到的时候重点介绍

public ConfirmView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);

        mSuccessPath = new Path();
        mPathMeasure = new PathMeasure(mSuccessPath, false);
        mRenderPaths = new ArrayList<>();

        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(0xFF0099CC);
        mPaint.setStrokeWidth(STROKEN_WIDTH);
        mPaint.setStrokeCap(Paint.Cap.ROUND);

        oval = new RectF();
    }

那么调用了animatedWithState()之后,进行了什么操作呢?

public void animatedWithState(State state) {

        if (mCurrentState != state) {
            mCurrentState = state;
            if (mPhareAnimator != null && mPhareAnimator.isRunning()) {
                stopPhareAnimation();
            }
            switch (state) {
                case Fail:
                case Success:
                    updatePath();
                    if (mCircleAnimator != null && mCircleAnimator.isRunning()) {
                        mCircleAngle = (Float) mCircleAnimator.getAnimatedValue();
                        mCircleAnimator.end();
                    }

                    if ((mStartAngleAnimator == null || !mStartAngleAnimator.isRunning() || !mStartAngleAnimator.isStarted()) &&
                            (mEndAngleAnimator == null || !mEndAngleAnimator.isRunning() || !mEndAngleAnimator.isStarted())) {
                        mStartAngle = 360;
                        mEndAngle = 0;
                        startPhareAnimation();
                    }

                    break;
                case Progressing:
                    mCircleAngle = 0;
                    startCircleAnimation();
                    break;
            }
        }

    }

结合着上面的代码,我简单解释一下。

首先进行重复性的判断,如果当前所处的状态与要改变的状态相同则不进行操作。

接下来,对动画状态进行了判断,mPhareAnimator是用来实现√和×的动画绘制效果的,如果正在运行,则停掉。

再往下的一个switch则是开始真正的操作了,updatePath()是更新Path,一会重点看下,mCircleAnimator这个则是实现外部弧形的偏移量的控制的,现在看不明白也没事,重点看下下面的代码,当mStartAngleAnimator和mEndAngleAnimator都不在运行状态的时候(这两个Animator是为了控制外部弧形的起点和终点的),会进入下面的代码,

mStartAngle = 360;
mEndAngle = 0;
startPhareAnimation();

mStartAngle和mEndAngle分别代表起点转过的角度和终点转过的角度,然后就startPhareAnimation(),这个时候,真正的绘制√和×的动画才开始执行。

如果是Progressing呢,则执行下面的代码,重置mCircleAngle,startCircleAnimation()这个方法是绘制外部的弧

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值