100字范文,内容丰富有趣,生活中的好帮手!
100字范文 > 【自定义控件】仿支付宝支付动画

【自定义控件】仿支付宝支付动画

时间:2022-07-21 11:10:06

相关推荐

【自定义控件】仿支付宝支付动画

作为国民级应用,想必大家对于支付宝并不陌生,作为一名程序猿,经常会被支付宝各种绚丽的界面所吸引,不禁深思,这个功能如何使实现?就好比支付宝的支付动画,究竟是怎么完成的呢?

PathMeasure

PathMeasure在android中,就好比一个测量仪,用来计算Path的一些信息,包括长度,坐标等信息。

构造方法

常用方法

效果图

初始化

先设定三种状态,分别对应加载、成功和失败,后面会用到

public static final int ALIPLAY_LOADING = 0;public static final int ALIPLAY_SUCCESS = 1;public static final int ALIPLAY_FAILED = 2;

三种状态都是一个圆形状,为了方便这里把圆心和半径直接写死,并且初始化Paint

private float radius = 100;private int centerX = 200;private int centerY = 200;paint = new Paint(Paint.ANTI_ALIAS_FLAG);paint.setColor(Color.BLACK);paint.setStyle(Paint.Style.STROKE);paint.setStrokeWidth(4);

准备工作之后,先画一个圆,无论是加载、成功或失败,这个圆都是必不可少的,通过Path画圆

circlePath = new Path();circlePath.addCircle(centerX, centerY, radius, Path.Direction.CW);

既然圆已经画出来了,不妨把对号和错号也画出来,无论是对号还是错号都不难,只要把点的对标计算出来,在通过Path画出来就简单得多了

对号

truePath = new Path();truePath.moveTo(centerX - radius / 2, centerY);truePath.lineTo(centerX, centerY + radius / 2);truePath.lineTo(centerX + radius / 2, centerY - radius / 3);//可以画个草图,很容易理解

错号

错号需要注意以下,两条相交的直线,是根据四个点画出来的

warPath1 = new Path();warPath1.moveTo(centerX - radius / 2, centerY - radius / 2);warPath1.lineTo(centerX + radius / 2, centerY + radius / 2);warPath2 = new Path();warPath2.moveTo(centerX + radius / 2, centerY - radius / 2);warPath2.lineTo(centerX - radius / 2, centerY + radius / 2);

要点

本文支付动画都是根据PathMeasure实现,在上面常用方法的表格中讲到了getSegment(float startD, float stopD, Path dst, boolean startWithMoveTo)

根据startD和stopD截取保存到dst中,因此还需要创建四个dstPath

dstCirclePath = new Path();dstTruePath = new Path();dstWarPath1 = new Path();dstWarPath2 = new Path();//错号的两条Path,因此对应两个dstcirclePathMeasure = new PathMeasure(circlePath, false);trueMeasure = new PathMeasure(truePath, false);warPathMeasure1 = new PathMeasure(warPath1, false);warPathMeasure2 = new PathMeasure(warPath2, false);

加载动画

通过动态图可以发现,加载动画是一个无限循环的状态,因此先创建一个循环动画,并且通过获取动画的完成进度,不断的重绘dstCirclePath

circleAnimator = ValueAnimator.ofFloat(0, 1);circleAnimator.setDuration(2000);circleAnimator.setRepeatCount(ValueAnimator.INFINITE);circleAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator valueAnimator) {//获取动画完成进度0·1circleCurValue = (float) valueAnimator.getAnimatedValue();invalidate();}});circleAnimator.start();@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);/*** 当进度未0.5-1时,路径起始点都是0,当进度为0.5-1时,起始点逐渐到达终点,当进度为1时, 起始重合*/if (viewStatue == Contants.ALIPLAY_LOADING) {float loadStop = circleCurValue * circlePathMeasure.getLength();float loadStart = (float) (loadStop - (0.5 - Math.abs(circleCurValue - 0.5)) * circlePathMeasure.getLength());dstCirclePath.reset();circlePathMeasure.getSegment(loadStart, loadStop, dstCirclePath, true);canvas.drawPath(dstCirclePath, paint);}}

成功动画

成功动画只是在加载动画的基础上稍微做了下改动,把外圆的无限循环去掉,不断重绘直到形成一个完整的圆,之后开始对号的动画与重绘

circleAnimator = ValueAnimator.ofFloat(0, 1);circleAnimator.setDuration(2000);circleAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator valueAnimator) {circleCurValue = (float) valueAnimator.getAnimatedValue();invalidate();if (circleCurValue == 1) {//当外圆动画完成后,对号动画开始启动trueAnimator.start();}}});circleAnimator.start();trueAnimator = ValueAnimator.ofFloat(0, 1);trueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator valueAnimator) {trueCurValue = (float) valueAnimator.getAnimatedValue();invalidate();}});trueAnimator.setDuration(2000);@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if (viewStatue == Contants.ALIPLAY_SUCCESS) {//与加载的区别,从0-1不断重绘float circleStop = circlePathMeasure.getLength() * circleCurValue;dstCirclePath.reset();circlePathMeasure.getSegment(0, circleStop, dstCirclePath, true);canvas.drawPath(dstCirclePath, paint);float trueStop = trueMeasure.getLength() * trueCurValue;dstTruePath.reset();trueMeasure.getSegment(0, trueStop, dstTruePath, true);canvas.drawPath(dstTruePath, paint);}}

失败动画

失败动画和成功动画差不多,只是注意下错号两条直线的动画的先后顺序即可

circleAnimator = ValueAnimator.ofFloat(0, 1);circleAnimator.setDuration(2000);circleAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator valueAnimator) {circleCurValue = (float) valueAnimator.getAnimatedValue();invalidate();if (circleCurValue == 1) {warAnimator1.start();}}});circleAnimator.start();warAnimator1 = ValueAnimator.ofFloat(0, 1);warAnimator1.setDuration(1000);warAnimator1.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator valueAnimator) {warCurValue1 = (float) valueAnimator.getAnimatedValue();invalidate();if (warCurValue1 == 1) {warAnimator2.start();}}});warAnimator2 = ValueAnimator.ofFloat(0, 1);warAnimator2.setDuration(1000);warAnimator2.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator valueAnimator) {warCurValue2 = (float) valueAnimator.getAnimatedValue();invalidate();}});@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if (viewStatue == Contants.ALIPLAY_FAILED) {float circleStop = circlePathMeasure.getLength() * circleCurValue;dstCirclePath.reset();circlePathMeasure.getSegment(0, circleStop, dstCirclePath, true);canvas.drawPath(dstCirclePath, paint);float warStop1 = warCurValue1 * warPathMeasure1.getLength();dstWarPath1.reset();warPathMeasure1.getSegment(0, warStop1, dstWarPath1, true);canvas.drawPath(dstWarPath1, paint);float warStop2 = warCurValue2 * warPathMeasure2.getLength();dstWarPath2.reset();warPathMeasure2.getSegment(0, warStop2, dstWarPath2, true);canvas.drawPath(dstWarPath2, paint);}}

注意

例子中有三个按钮,分别是加载按钮,成功按钮,失败按钮,需要注意的是,每次点击成功或失败按钮时候都需要先把成功动画进度和失败动画进度归零,不然二次点击时候,对号和错号都会直接显示之后再根据动画进度重绘。

public void success() {if (trueAnimator != null) {trueAnimator.cancel();}if (circleAnimator != null) {circleAnimator.cancel();}trueCurValue = 0;aniMator(Contants.ALIPLAY_SUCCESS);}public void failed() {if (trueAnimator != null) {trueAnimator.cancel();}if (circleAnimator != null) {circleAnimator.cancel();}warCurValue1 = 0;warCurValue2 = 0;aniMator(Contants.ALIPLAY_FAILED);}

源码

/qylfzy/CustomView

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。