android path自动闭合,Android自定义View系列之Path绘制仿支付宝支付成功动画

前言

使用支付宝付款时,我们可以看到成功或者失败都会有个动画提示,如果我们需要做这样的效果的话,当然,你可以让设计师给你做个GIF,但是我们知道图像比较耗内存的,我们自己可以用代码实现还是代码实现好点吧。

效果

b5329513f2b9368226a5d284854a6a62.gif

实现方法

首先我们需要了解PathMeasure这个类,这个类我们可以理解为用来管理Path。我们主要看几个方法。

PathMeasure(): 构造方法 ,实例化一个对象

PathMeasure(Path path,boolean isClosed):传入Path对象和是否闭合,path对象不能为空

getLength():获取当前轮廓、外形的总长度, 如果没有设置Path对象,返回0

getSegment(float startD,float stopD,Path dst,boolean startWithMoveTo):调用这个方法,我们可以获取到指定范围内的一段轮廓,存入到dst参数中。所以,这个方法传入的参数分别为长度起始值、结束值、装这一段路径的Path对象、是否MoveTo。另外,这个方法返回值为Boolean类型,如果getLength为0的话,返回false,或者startD > stopD,同样返回false。

setPath(Path path , boolean isClosed):给当前PathMeasure对象设置Path

nextContour():移动到下一个轮廓

然后我们需要动起来,我们知道invalidate()方法可以刷新界面,也就是重新调用onDraw()方法,所以我们要不停调用invalidate方法,在onDraw方法中改变参数,这样实现动的效果。所以可以用到刚刚介绍的getSegment方法,不断改变获取的范围,从0 * getLength,到1 * getLength,最后绘制完整。所以我们需要一个在一秒内或两秒内一个从0到1的值的变化,so,我们使用ValueAnimator这个类来实现。

//实例化对象

mCircleAnimator = ValueAnimator.ofFloat(0, 1);

//设置时长为1000ms

mCircleAnimator.setDuration(1000);

//开始动画

mCircleAnimator.start();

//设置动画监听

mCircleAnimator.addUpdateListener(this);

动画开始后,在监听方法中获取当前进度并且重绘图像

mCirclePercent = (float)animation.getAnimatedValue();

invalidate();

在onDraw方法中,绘制图像

//画圆

mPathCircle.addCircle(getWidth() / 2, getWidth() / 2, getWidth() / 2 - mLineWidth, Path.Direction.CW);

mPathMeasure.setPath(mPathCircle, false);

mPathMeasure.getSegment(0, mCirclePercent * mPathMeasure.getLength(), mPathCircleDst, true);

canvas.drawPath(mPathCircleDst, mPaint);

附上源码,欢迎点评

package com.mintmedical.wavedemo;

import android.animation.ValueAnimator;

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.Path;

import android.graphics.PathMeasure;

import android.util.AttributeSet;

import android.util.Log;

import android.view.View;

/**

* Created by MooreLi on 2016/12/12.

*/

public class ResultAnimation extends View implements ValueAnimator.AnimatorUpdateListener {

private Context mContext;

/**

* paint对象

*/

private Paint mPaint;

/**

* Path和对应的空Path用来填充

*/

private Path mPathCircle;

private Path mPathCircleDst;

private Path mPathRight;

private Path mPathRightDst;

private Path mPathWrong1;

private Path mPathWrong2;

private Path mPathWrong1Dst;

private Path mPathWrong2Dst;

/**

* Path管理

*/

private PathMeasure mPathMeasure;

/**

* 动画

*/

private ValueAnimator mCircleAnimator;

private ValueAnimator mRightAnimator;

private ValueAnimator mWrong1Animator;

private ValueAnimator mWrong2Animator;

/**

* 当前绘制进度占总Path长度百分比

*/

private float mCirclePercent;

private float mRightPercent;

private float mWrong1Percent;

private float mWrong2Percent;

/**

* 线宽

*/

private int mLineWidth;

/**

* 正确动画 错误动画

*/

public static final int RESULT_RIGHT = 1;

public static final int RESULT_WRONG = 2;

/**

* 当前结果类型

*/

private int mResultType = RESULT_WRONG;

public ResultAnimation(Context context) {

super(context);

mContext = context;

init();

}

public ResultAnimation(Context context, AttributeSet attrs) {

super(context, attrs);

mContext = context;

init();

}

public ResultAnimation(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

mContext = context;

init();

}

private void init() {

mLineWidth = dp2px(3);

mPaint = new Paint();

mPaint.setAntiAlias(true);

mPaint.setStrokeWidth(mLineWidth);

mPaint.setStyle(Paint.Style.STROKE);

mPaint.setColor(Color.GREEN);

initPath();

}

private void initPath() {

mPathCircle = new Path();

mPathCircleDst = new Path();

mPathRight = new Path();

mPathRightDst = new Path();

mPathWrong1 = new Path();

mPathWrong2 = new Path();

mPathWrong1Dst = new Path();

mPathWrong2Dst = new Path();

mPathMeasure = new PathMeasure();

//实例化对象

mCircleAnimator = ValueAnimator.ofFloat(0, 1);

//设置时长为1000ms

mCircleAnimator.setDuration(1000);

//开始动画

mCircleAnimator.start();

//设置动画监听

mCircleAnimator.addUpdateListener(this);

mRightAnimator = ValueAnimator.ofFloat(0, 1);

mRightAnimator.setDuration(500);

mRightAnimator.addUpdateListener(this);

mWrong1Animator = ValueAnimator.ofFloat(0, 1);

mWrong1Animator.setDuration(300);

mWrong1Animator.addUpdateListener(this);

mWrong2Animator = ValueAnimator.ofFloat(0, 1);

mWrong2Animator.setDuration(300);

mWrong2Animator.addUpdateListener(this);

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

if (mResultType == RESULT_RIGHT) {

mPaint.setColor(Color.GREEN);

} else {

mPaint.setColor(Color.RED);

}

//画圆

mPathCircle.addCircle(getWidth() / 2, getWidth() / 2, getWidth() / 2 - mLineWidth, Path.Direction.CW);

mPathMeasure.setPath(mPathCircle, false);

mPathMeasure.getSegment(0, mCirclePercent * mPathMeasure.getLength(), mPathCircleDst, true);

canvas.drawPath(mPathCircleDst, mPaint);

if (mResultType == RESULT_RIGHT) {

//画对勾

mPathRight.moveTo(getWidth() / 4, getWidth() / 2);

mPathRight.lineTo(getWidth() / 2, getWidth() / 4 * 3);

mPathRight.lineTo(getWidth() / 4 * 3, getWidth() / 4);

if (mCirclePercent == 1) {

mPathMeasure.nextContour();

mPathMeasure.setPath(mPathRight, false);

mPathMeasure.getSegment(0, mRightPercent * mPathMeasure.getLength(), mPathRightDst, true);

canvas.drawPath(mPathRightDst, mPaint);

}

} else {

mPathWrong1.moveTo(getWidth() / 4 * 3, getWidth() / 4);

mPathWrong1.lineTo(getWidth() / 4, getWidth() / 4 * 3);

mPathWrong2.moveTo(getWidth() / 4, getWidth() / 4);

mPathWrong2.lineTo(getWidth() / 4 * 3, getWidth() / 4 * 3);

if (mCirclePercent == 1) {

mPathMeasure.nextContour();

mPathMeasure.setPath(mPathWrong1, false);

mPathMeasure.getSegment(0, mWrong1Percent * mPathMeasure.getLength(), mPathWrong1Dst, true);

canvas.drawPath(mPathWrong1Dst, mPaint);

}

if (mWrong1Percent == 1) {

mPathMeasure.nextContour();

mPathMeasure.setPath(mPathWrong2, false);

mPathMeasure.getSegment(0, mWrong2Percent * mPathMeasure.getLength(), mPathWrong2Dst, true);

canvas.drawPath(mPathWrong2Dst, mPaint);

}

}

}

private int dp2px(int dp) {

float scale = mContext.getResources().getDisplayMetrics().density;

return (int) (scale * dp + 0.5f);

}

@Override

public void onAnimationUpdate(ValueAnimator animation) {

//圆形动画

if (animation.equals(mCircleAnimator)) {

mCirclePercent = (float) animation.getAnimatedValue();

invalidate();

Log.e("TEST","percent:"+mCirclePercent);

if (mCirclePercent == 1) {

if (mResultType == RESULT_RIGHT)

mRightAnimator.start();

else

mWrong1Animator.start();

}

}

//正确时 对勾动画

else if (animation.equals(mRightAnimator)) {

mRightPercent = (float) animation.getAnimatedValue();

invalidate();

}

//错误时 右侧动画

else if (animation.equals(mWrong1Animator)) {

mWrong1Percent = (float) animation.getAnimatedValue();

invalidate();

if (mWrong1Percent == 1) {

mWrong2Animator.start();

}

}

//错误时 左侧动画

else if (animation.equals(mWrong2Animator)) {

mWrong2Percent = (float) animation.getAnimatedValue();

invalidate();

}

}

public void setmResultType(int mResultType) {

this.mResultType = mResultType;

invalidate();

}

/**

* 固定写死了宽高,可重新手动调配

*

* @param widthMeasureSpec

* @param heightMeasureSpec

*/

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

setMeasuredDimension(dp2px(50), dp2px(50));

}

}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值