欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android自定义View系列之Path绘制仿支付宝支付成功动画

程序员文章站 2024-02-27 23:25:21
前言 使用支付宝付款时,我们可以看到成功或者失败都会有个动画提示,如果我们需要做这样的效果的话,当然,你可以让设计师给你做个gif,但是我们知道图像比较耗内存的,我们自己...

前言

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

效果

Android自定义View系列之Path绘制仿支付宝支付成功动画

实现方法

首先我们需要了解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));
 }
}

github地址:

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