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

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

程序员文章站 2024-02-24 18:42:40
实现原理 首先就是自定义个waveview 继承view,然后再waveview 内部实现代码逻辑:       ①...

实现原理

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

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

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

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

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

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

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

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

闲话就不说了,先上

效果图

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

示例代码如下

调用的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>

总结

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