当前位置: 移动技术网 > IT编程>移动开发>Android > Android中PathMeasure仿支付宝支付动画

Android中PathMeasure仿支付宝支付动画

2019年07月24日  | 移动技术网IT编程  | 我要评论

王小二丧尸漫画,南阳新闻网,世纪金源成人用品

前言

在 android 自定义 view 中,path 可能用的比较多,pathmeasure 可能用的比较少,就我而言,以前也没有使用过 pathmeasure 这个 api,看到别人用 pathmeasure 和 valueanimator 结合在一起完成了很好的动画效果,于是我也学习下 pathmeasure ,此处记录下。

pathmeasure

构造器:

forceclosed 含义:

// 创建一个 path 对象
path = new path();
path.moveto(20, 20);
path.lineto(200, 20);
path.lineto(200, 400);

在ondraw(canvas canvas) 中绘制 path

@override
 protected void ondraw(canvas canvas) {
  destpath.reset();
  destpath.lineto(0, 0);
  pathmeasure.setpath(path, true);
  log.e("debug", "pathmeasure.getlength() = " + pathmeasure.getlength());
  pathmeasure.getsegment(0, pathmeasure.getlength() * curvalue, destpath, true);
canvas.drawpath(destpath, paint); // 绘制线段路径

 }

当 pathmeasure.setpath(path,false) 时:

这里写图片描述

这里写图片描述

当 pathmeasure.setpath(path,true) 时:

这里写图片描述

这里写图片描述

可以看到:当 forceclosed = true 时, path 进行了闭合,相应的 path 长度也变长了,即 算上了斜边的长度。

仿支付宝支付动画 view - loadingview

效果:

这里写图片描述

思路:

绘制对号,叉号,主要是通过 valueanimator 结合 getsegment() 不断绘制新的弧形段,其中,叉号由两个 path 组成,在第一个 path 绘制完成时,需要调用 pathmeasure.nextcontour() 跳转到另一个 path。

getsegment() 将获取的片段填充到 destpath 中,在 android 4.4 及以下版本中,不能绘制,需要调用 destpath.reset(),destpath.line(0,0)

loadingview 完整代码:

public class loadingview extends view {

  private final int default_color = color.black; // 默认圆弧颜色

  private final int default_stroke_width = dp2px(2); // 默认圆弧宽度

  private final boolean default_is_show_result = false; // 默认不显示加载结果

  private final int default_view_width = dp2px(50); // 控件默认宽度

  private final int default_view_height = dp2px(50); // 控件默认高度

  private int color; // 圆弧颜色

  private int strokewidth;  // 圆弧宽度

  private boolean isshowresult;  // 是否显示加载结果状态

  private paint paint; // 画笔

  private int mwidth; // 控件宽度

  private int mheight; // 控件高度

  private int radius;  // 圆弧所在圆的半径

  private int halfstrokewidth; // 画笔宽度的一半


  private int rotatedelta = 4;

  private int curangle = 0;

  private int minangle = -90;

  private int startangle = -90; // 上方顶点

  private int endangle = 0;

  private rectf rectf;

  private stateenum stateenum = stateenum.loading;

  private path successpath;

  private path rightfailpath;

  private path leftfailpath;

  private valueanimator successanimator;

  private valueanimator rightfailanimator;

  private valueanimator leftfailanimator;

  private pathmeasure pathmeasure;

  private float successvalue;

  private float rightfailvalue;

  private float leftfailvalue;

  private path destpath;

  private animatorset animatorset;

  public loadingview(context context) {
    this(context, null);
  }

  public loadingview(context context, attributeset attrs) {
    super(context, attrs);
    init(context, attrs);
  }


  private void init(context context, attributeset attrs) {
    typedarray typedarray = null;
    try {
      typedarray = context.obtainstyledattributes(attrs, r.styleable.loadingview);
      color = typedarray.getcolor(r.styleable.loadingview_color, default_color);
      strokewidth = (int) typedarray.getdimension(r.styleable.loadingview_storkewidth, default_stroke_width);
      isshowresult = typedarray.getboolean(r.styleable.loadingview_isshowresult, default_is_show_result);
    } catch (exception e) {
      e.printstacktrace();
    } finally {
      if (typedarray != null) {
        typedarray.recycle();
      }
    }
    paint = createpaint(color, strokewidth, paint.style.stroke);
  }


  @override
  protected void onsizechanged(int w, int h, int oldw, int oldh) {
    super.onsizechanged(w, h, oldw, oldh);
    mwidth = w;
    mheight = h;
    log.i("debug", "getmeasurewidth() = " + getmeasuredwidth());
    log.i("debug", "getmeasureheight() = " + getmeasuredheight());

    radius = math.min(mwidth, mheight) / 2;
    halfstrokewidth = strokewidth / 2;

    rectf = new rectf(halfstrokewidth - radius, halfstrokewidth - radius,
        radius - halfstrokewidth, radius - halfstrokewidth);
    // success path
    successpath = new path();
    successpath.moveto(-radius * 2 / 3f, 0f);
    successpath.lineto(-radius / 8f, radius / 2f);
    successpath.lineto(radius / 2, -radius / 3);
    // fail path ,right top to left bottom
    rightfailpath = new path();
    rightfailpath.moveto(radius / 3f, -radius / 3f);
    rightfailpath.lineto(-radius / 3f, radius / 3f);

    // fail path, left top to right bottom
    leftfailpath = new path();
    leftfailpath.moveto(-radius / 3f, -radius / 3f);
    leftfailpath.lineto(radius / 3f, radius / 3f);

    pathmeasure = new pathmeasure();

    destpath = new path();

    initsuccessanimator();
    initfailanimator();
  }

  private void initsuccessanimator() {
//    pathmeasure.setpath(successpath, false);
    successanimator = valueanimator.offloat(0, 1f);
    successanimator.setduration(1000);
    successanimator.setinterpolator(new linearinterpolator());
    successanimator.addupdatelistener(new valueanimator.animatorupdatelistener() {

      @override
      public void onanimationupdate(valueanimator animation) {
        successvalue = (float) animation.getanimatedvalue();
        invalidate();
      }
    });
  }


  private void initfailanimator() {
//    pathmeasure.setpath(rightfailpath, false);
    rightfailanimator = valueanimator.offloat(0, 1f);
    rightfailanimator.addupdatelistener(new valueanimator.animatorupdatelistener() {

      @override
      public void onanimationupdate(valueanimator animation) {
        rightfailvalue = (float) animation.getanimatedvalue();
        invalidate();
      }
    });

//    pathmeasure.setpath(leftfailpath, false);
    leftfailanimator = valueanimator.offloat(0, 1f);
    leftfailanimator.addupdatelistener(new valueanimator.animatorupdatelistener() {
      @override
      public void onanimationupdate(valueanimator animation) {
        leftfailvalue = (float) animation.getanimatedvalue();
        invalidate();
      }
    });

    animatorset = new animatorset();
    animatorset.play(leftfailanimator).after(rightfailanimator);
    animatorset.setduration(500);
    animatorset.setinterpolator(new linearinterpolator());


  }


  /**
   * 测量控件的宽高,当测量模式不是精确模式时,设置默认宽高
   *
   * @param widthmeasurespec
   * @param heightmeasurespec
   */
  @override
  protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
    int widthmode = measurespec.getmode(widthmeasurespec);
    int heightmode = measurespec.getmode(heightmeasurespec);
    if (widthmode == measurespec.at_most || widthmode == measurespec.unspecified) {
      widthmeasurespec = measurespec.makemeasurespec(default_view_width, measurespec.exactly);
    }
    if (heightmode == measurespec.at_most || heightmode == measurespec.unspecified) {
      heightmeasurespec = measurespec.makemeasurespec(default_view_height, measurespec.exactly);

    }
    super.onmeasure(widthmeasurespec, heightmeasurespec);
  }


  @override
  protected void ondraw(canvas canvas) {
    canvas.save();
    canvas.translate(mwidth / 2, mheight / 2);
    destpath.reset();
    destpath.lineto(0, 0);  // destpath
    if (stateenum == stateenum.loading) {
      if (endangle >= 300 || startangle > minangle) {
        startangle += 6;
        if (endangle > 20) {
          endangle -= 6;
        }
      }
      if (startangle > minangle + 300) {
        minangle = startangle;
        endangle = 20;
      }
      canvas.rotate(curangle += rotatedelta, 0, 0);//旋转rotatedelta=4的弧长
      canvas.drawarc(rectf, startangle, endangle, false, paint);
      // endangle += 6 放在 drawarc()后面,是防止刚进入时,突兀的显示了一段圆弧
      if (startangle == minangle) {
        endangle += 6;
      }
      invalidate();
    }
    if (isshowresult) {
      if (stateenum == stateenum.load_success) {
        pathmeasure.setpath(successpath, false);
        canvas.drawcircle(0, 0, radius - halfstrokewidth, paint);
        pathmeasure.getsegment(0, successvalue * pathmeasure.getlength(), destpath, true);
        canvas.drawpath(destpath, paint);
      } else if (stateenum == stateenum.load_failed) {
        canvas.drawcircle(0, 0, radius - halfstrokewidth, paint);
        pathmeasure.setpath(rightfailpath, false);
        pathmeasure.getsegment(0, rightfailvalue * pathmeasure.getlength(), destpath, true);
        if (rightfailvalue == 1) {
          pathmeasure.setpath(leftfailpath, false);
          pathmeasure.nextcontour();
          pathmeasure.getsegment(0, leftfailvalue * pathmeasure.getlength(), destpath, true);
        }
        canvas.drawpath(destpath, paint);
      }
    }
    canvas.restore();

  }


  public void updatestate(stateenum stateenum) {
    this.stateenum = stateenum;
    if (stateenum == stateenum.load_success) {
      successanimator.start();
    } else if (stateenum == stateenum.load_failed) {
      animatorset.start();
    }
  }


  public enum stateenum {
    loading, // 正在加载
    load_success,  // 加载成功,显示对号
    load_failed   // 加载失败,显示叉号
  }


  /**
   * 创建画笔
   *
   * @param color    画笔颜色
   * @param strokewidth 画笔宽度
   * @param style    画笔样式
   * @return
   */
  private paint createpaint(int color, int strokewidth, paint.style style) {
    paint paint = new paint(paint.anti_alias_flag);
    paint.setstrokecap(paint.cap.round);
    paint.setstrokejoin(paint.join.round);
    paint.setcolor(color);
    paint.setstrokewidth(strokewidth);
    paint.setstyle(style);
    return paint;
  }


  /**
   * dp 转换成 px
   *
   * @param dpvalue
   * @return
   */
  private int dp2px(int dpvalue) {
    return (int) typedvalue.applydimension(typedvalue.complex_unit_dip, dpvalue, getresources().getdisplaymetrics());
  }

}

github : https://github.com/xing16/loadingview

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

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网