当前位置: 移动技术网 > 移动技术>移动开发>Android > Android自定义WaveView实现波浪进度效果

Android自定义WaveView实现波浪进度效果

2019年07月24日  | 移动技术网移动技术  | 我要评论
实现原理 首先就是自定义个waveview 继承view,然后再waveview 内部实现代码逻辑:       ①

实现原理

首先就是自定义个waveview 继承view,然后再waveview 内部实现代码逻辑:

      ① 水波就波嘛? sin函数? 贝塞尔曲线? 都行,这里就用二阶贝塞 尔曲线去画吧

      ② 波要动嘛,怎么动呢?线程? 好吧 这里用了个handler。

      ③绘制波首先要找点,那么在onmeasure()里找出需要的点咯,这里就暂时展示一个波段吧,一个波长移动左边不就没了?ok 那就两个波吧,吼吼,两个波(猥琐男潜质表露无遗啊)。接下来就是handler 结合 ondraw()绘制。ok,那就先看我word绘制的粗瘪的波动图,请看vcr,oh,no... gif

意思就是波平移一个波长之后回到初始位置继续平移循环。

好吧,有人说了,这么简单的逻辑你要啰嗦那么多???

好吧,我承认,我有唐僧的潜质。。。

闲话就不说了,先上

效果图


示例代码如下

调用的activity

 * created by liudong on 2016/12/22.
 * email:15002102128@126.com
 */

public class waveactivity extends activity {
 ld_waveview waveview;//方形
 ld_waveview wavecircleview;//圆形
 private int progrees=0;//进度
 private handler mhandler=new handler(){
  @override
  public void handlemessage(message msg) {
   if (progrees==100) progrees=0;
   log.i("progress",progrees+"");
   waveview.setmprogress(progrees++);
   wavecircleview.setmprogress(progrees++);
   mhandler.sendemptymessagedelayed(0,100);
  }
 };
 @override
 protected void oncreate(bundle savedinstancestate) {
  super.oncreate(savedinstancestate);
  setcontentview(r.layout.activity_wave);
  waveview= (ld_waveview) findviewbyid(r.id.waveview);
  wavecircleview= (ld_waveview) findviewbyid(r.id.waveviewcircle);
  mhandler.sendemptymessagedelayed(0,10);
 }
}

xml布局

<?xml version="1.0" encoding="utf-8"?>
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:app="http://schemas.android.com/apk/res-auto"
 android:orientation="vertical" android:layout_width="match_parent"
 android:background="@color/ld_white"
 android:layout_height="match_parent">
 <com.dadong.ld_tools.widget.ld_waveview
  android:id="@+id/waveviewcircle"
  android:layout_margintop="20dp"
  android:layout_width="100dp"
  android:layout_centerhorizontal="true"
  android:layout_height="100dp"
  app:wave_color="@color/ld_black"
  app:wave_circle="true"
  />
 <com.dadong.ld_tools.widget.ld_waveview
  android:id="@+id/waveview"
  android:layout_width="100dp"
  android:layout_height="100dp"
  app:wave_color="@color/ld_black"
  app:wave_circle="false"
  android:layout_centerinparent="true" />
</relativelayout>

自定义waveview

/**
 * created by liudong on 2016/12/23.
 * email:15002102128@126.com
 */

public class ld_waveview extends view {

 private int mprogress;//进度
 private int mtimestep = 10;//时间间隔
 private int mspeed = 5;//波单次移动的距离
 private int mviewheight;//视图宽高
 private int mviewwidth;//视图宽度
 private int mlevelline;// 基准线


 private int mwavelength;//波长 暂定view宽度为一个波长
 private int mstrokewidth;//园的线宽
 private rectf rectf;//圆环区域
 private int mwaveheight;//波峰高度
 private int mleftwavemovelength;//波平移的距离,用来控制波的起点位置
 private int mwavecolor;//波的颜色
 private paint mpaint;//画笔
 private paint mcirclepaint;//圆环画笔
 private paint mborderpaint;//边界画笔
 private int mborderwidth=4;//边界宽度
 private paint mtextpaint;//文字画笔
 private path mpath;//绘画线
 private list<point> mpoints;//点的集合
 private boolean ismeasure = false;//是否已测量过
 private boolean iscircle=false;//是否圆形默认false,可属性代码设置
 //处理消息
 private handler handler = new handler() {
  @override
  public void handlemessage(message msg) {

   initwavemove();
  }
 };

 /**
  * 初始化波的移动
  */
 private void initwavemove(){
  mleftwavemovelength+=mspeed;//波向右移动距离增加mspeed;
  if (mleftwavemovelength>=mwavelength){//当增加到一个波长时回复到0
   mleftwavemovelength=0;
  }
  invalidate();

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

 public ld_waveview(context context, attributeset attrs) {
  this(context, attrs, 0);
 }

 public ld_waveview(context context, attributeset attrs, int defstyleattr) {
  super(context, attrs, defstyleattr);

  getattr(context, attrs, defstyleattr);
  init();

 }

 /**
  * 初始化画笔
  */
 private void init() {
  mpoints = new arraylist<point>();
  //波浪轨迹画笔
  mpaint = new paint();
  mpaint.setantialias(true);
  mpaint.setcolor(mwavecolor);
  mpaint.setstyle(paint.style.fill_and_stroke);


  mpath = new path();


  //文字画笔
  mtextpaint=new paint();
  mtextpaint.setcolor(color.red);
  mtextpaint.settextalign(paint.align.center);
  mtextpaint.settextsize(48);


  //圆环画笔
  mcirclepaint=new paint();
  mcirclepaint.setantialias(true);
  mcirclepaint.setcolor(color.white);
  mcirclepaint.setstyle(paint.style.stroke);
  //边界线画笔
  mborderpaint=new paint();
  mborderpaint.setantialias(true);
  mborderpaint.setcolor(mwavecolor);
  mborderpaint.setstrokewidth(mborderwidth);
  mborderpaint.setstyle(paint.style.stroke);


 }

 /**
  * 获取自定义的属性值
  *
  * @param attrs
  */
 private void getattr(context context, attributeset attrs, int defstyle) {

  typedarray a = context.obtainstyledattributes(attrs, r.styleable.ld_waveview, defstyle, 0);

  mwavecolor = a.getcolor(r.styleable.ld_waveview_wave_color, color.red);
  iscircle=a.getboolean(r.styleable.ld_waveview_wave_circle,false);
  a.recycle();

 }


 /**
  *
  * @param widthmeasurespec
  * @param heightmeasurespec
  */
 @override
 protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {

  super.onmeasure(widthmeasurespec, heightmeasurespec);
  if (!ismeasure&&math.abs(getmeasuredheight()-getmeasuredwidth())<50) {//只计算一次就够了 ,relativelayout的时候要绘制两次 加个宽高判断
   mviewheight = getmeasuredheight();
   mviewwidth = getmeasuredwidth();
   mlevelline = mviewheight; //初始化波的准位线  起始位视图最底部
   {
    mlevelline = mviewheight * (100-mprogress) / 100;
    if (mlevelline < 0) mlevelline = 0;
   }
   //计算波峰值
   mwaveheight = mviewheight / 20;//波峰暂定为view高度的1/20,如果需要设置 可设置set方法赋值;
   mwavelength = getmeasuredwidth();

   //计算所有的点 这里取宽度为整个波长 往左再延伸一个波长 两个波长则需要9个点
   for (int i = 0; i < 9; i++) {
    int y = 0;
    switch (i % 4) {
     case 0:
      y = mviewheight;
      break;
     case 1:
      y =mviewheight+ mwaveheight;
      break;
     case 2:
      y = mviewheight;
      break;
     case 3:
      y = mviewheight-mwaveheight;
      break;
    }
    point point = new point(-mwavelength + i * mwavelength / 4, y);
    mpoints.add(point);
   }
   /**
    * 计算圆环宽度
    */
   int mincircleradius=mviewheight<mviewwidth?mviewheight/2:mviewwidth/2;//内切圆半径

   int mcircumcircleradius= (int) (math.sqrt((float)(math.pow(mviewheight/2,2)+math.pow(mviewwidth/2,2)))+0.5);//外接圆半径
   int radius=mcircumcircleradius/2+mincircleradius/2;

   rectf=new rectf(mviewwidth/2-radius,mviewheight/2-radius,mviewwidth/2+radius,mviewheight/2+radius);
   mstrokewidth=mcircumcircleradius-mincircleradius;
   mcirclepaint.setstrokewidth(mstrokewidth);//线是有宽度的 采用了这种方式画圆环
   ismeasure = true;
  }
 }

 @override
 protected void ondraw(canvas canvas) {
  super.ondraw(canvas);
  /**
   * 绘制线条
   */
  mpath.reset();
  int i = 0;
  mpath.moveto(mpoints.get(0).getx()+mleftwavemovelength, mpoints.get(0).gety()-mviewheight*mprogress/100);
  for (; i < mpoints.size() - 2; i += 2) {
   mpath.quadto(mpoints.get(i + 1).getx()+mleftwavemovelength, mpoints.get(i + 1).gety()-mviewheight*mprogress/100, mpoints.get(i + 2).getx()+mleftwavemovelength, mpoints.get(i + 2).gety()-mviewheight*mprogress/100);
  }
  mpath.lineto(mpoints.get(i).getx()+mleftwavemovelength, mviewheight);
  mpath.lineto(mpoints.get(0).getx()+mleftwavemovelength, mviewheight);
  mpath.close();
  /**
   * 绘制轨迹
   */
  canvas.drawpath(mpath,mpaint);
  rect rect = new rect();

  string progress=string.format("%d%%",mprogress);
  mtextpaint.gettextbounds(progress,0,progress.length(), rect);
  int textheight = rect.height();
  if (mprogress>=50)//如果进度达到50 颜色变为白色,没办法啊,进度在中间 不变颜色看不到
   mtextpaint.setcolor(color.white);
  else
  mtextpaint.setcolor(mwavecolor);
  canvas.drawtext(progress,0,progress.length(),mviewwidth/2,mviewheight/2+textheight/2,mtextpaint);

  if (iscircle) {
   /**
    * 绘制圆环
    */

   canvas.drawarc(rectf, 0, 360, true, mcirclepaint);
   paint circlepaint = new paint();
   circlepaint.setstrokewidth(5);
   circlepaint.setcolor(color.white);
   circlepaint.setantialias(true);
   circlepaint.setstyle(paint.style.stroke);
   canvas.drawcircle(mviewwidth / 2, mviewheight / 2, mviewheight / 2, circlepaint);
   /**
    * 绘制边界
    */

   mborderpaint.setstrokewidth(mborderwidth/2);
  canvas.drawcircle(mviewwidth/2,mviewheight/2,mviewheight/2-mborderwidth/2,mborderpaint);
  }else {
   /**
    * 绘制矩形边框
    */
   canvas.drawrect(0,0,mviewwidth,mviewheight,mborderpaint);
  }
  //
  handler.sendemptymessagedelayed(0,mtimestep);
 }

 /**
  * 设置进度 基准线
  * @param mprogress
  */
 public void setmprogress(int mprogress) {
  this.mprogress = mprogress;
  mlevelline=(100-mprogress)*mviewheight/100;
 }

 /**
  * 设置是否为圆形
  * @param circle
  */
 public void setcircle(boolean circle) {
  iscircle = circle;
 }
}

自定义属性

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <declare-styleable name="ld_waveview">
  <attr name="wave_color" format="color"></attr>
  <attr name="wave_circle" format="boolean"></attr>
 </declare-styleable>
</resources>

总结

好了,以上就是这篇文章的全部内容了,代码里备注应该还算比较清楚了,希望能对一些人有一些帮助,瑕疵不足之处欢迎指正,或者有好的建议。也可以留言交流。

如您对本文有疑问或者有任何想说的,请点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网