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

Android水波纹载入控件CircleWaterWaveView使用详解

程序员文章站 2022-06-23 14:57:56
一、效果图 本控件已上传github,欢迎star和fork,项目地址:circlewaterwaveview 二、设计思路 观察效果图,可以看出,该自定义控件由...

一、效果图

Android水波纹载入控件CircleWaterWaveView使用详解

本控件已上传github,欢迎star和fork,项目地址:circlewaterwaveview

二、设计思路

观察效果图,可以看出,该自定义控件由三个部分构成:外圆、内圆、正弦曲线。他们的关系如下图:

Android水波纹载入控件CircleWaterWaveView使用详解

因为控件是动态的,所以我们需要一个线程去不停地绘制,所以我选择了surfaceview来作为该控件地父类。该控件地核心是如何去绘制波浪,我采用如下的思路来进行内圆下部地绘制。利用内圆与正弦曲线地交集,来绘制。 

Android水波纹载入控件CircleWaterWaveView使用详解

核心代码如下:

/**
 * 绘制图像
 *
 * @author luxun
*/
  private void drawcanvas(canvas canvas) {
    if (canvas == null)
      return;
    //画背景圆圈
    canvas.setdrawfilter(new paintflagsdrawfilter(0, paint.anti_alias_flag | paint.filter_bitmap_flag));
    canvas.drawcircle(mcenterpoint.x, mcenterpoint.y, moutradius, moutcirclepaint);
    canvas.drawcircle(mcenterpoint.x, mcenterpoint.y, mradius, mcirclepaint);
    if (mstart) {
      //计算正弦曲线的路径
      int mh = mcenterpoint.y + mradius - mcurrenthight;
      int length = 2 * moutradius;
      path path = new path();
      path.moveto(0, mh);
      for (int i = 0; i < length; i++) {
        int x = i;
        int y = (int) (math.sin(math.toradians(x + mtranx) / amplitude) * mradius / increase);
        path.lineto(x, mh + y);
      }
      path.lineto(length, mh);
      path.lineto(length, mcenterpoint.y + mradius);
      path.lineto(0, mcenterpoint.y + mradius);
      path.lineto(0, mh);
      canvas.save();//保存画布状态
      //这里与圆形取交集,除去正弦曲线多画的部分
      path pc = new path();
      pc.addcircle(mcenterpoint.x, mcenterpoint.y, mradius, path.direction.ccw);
      canvas.clippath(pc, region.op.intersect);//切割画布
      canvas.drawpath(path, mwaterpaint);
      //绘制文字
      canvas.drawtext(flownum + "%", mcenterpoint.x, mcenterpoint.y + mtextsise / 2, mtextpaint);
      canvas.restore();//恢复画布状态
    }
  }

三、性能优化

绘制线程如下:

 /**
   * 绘制界面的线程
   *
   * @author luxun
 */
  private class renderthread implements runnable {
    @override
    public void run() {
      // 不停绘制界面,这里是异步绘制,不采用外部通知开启绘制的方式,水波根据数据更新才会开始增长
      while (isdrawing) {
        if (mwatertaget > mcurrenthight) {
          mcurrenthight = mcurrenthight + mupspeed;
          if (mwatertaget <= mcurrenthight) {
            mcurrenthight = mwatertaget;
          }
        }
        if (mstart) {
          if (mtranx > mradius) {
            mtranx = 0;
          }
          mtranx -= mwaterspeed;
        }
        drawui();
        systemclock.sleep(25);//控制刷新速率,减少cpu占用
      }
    }
  }

通过为surfaceholder添加监听,来控制绘制线程。当控件被隐藏不在前台显示时,自动结束绘制线程,当控件显示在前台时,再次开启绘制。

@override
  public void surfacecreated(surfaceholder surfaceholder) {
    isdrawing = true;
    new thread(renderthread).start();
  }

  @override
  public void surfacechanged(surfaceholder surfaceholder, int format, int width, int height) {
    int minlength = math.min(width, height);
    moutradius = minlength / 2;
    mradius = (int) (0.5 * (minlength - moutstrokewidth));
    mcenterpoint = new point(minlength / 2, minlength / 2);
    if (progress != 0) {
      setprogress(progress);
    }
  }

  @override
  public void surfacedestroyed(surfaceholder surfaceholder) {
    isdrawing = false;
  }

四、属性化

部分设置属性,除了通过代码设置外,同时也加入了在xml文件中,直接以属性赋值的操作。

app:textcolor="#00ff00"
app:watercolor="#00ff00"
app:strokecolor="#00ff00"
app:backgroudcolor="#00ff00"
app:amplitude="1.0"[水波振幅]
app:max="1000"
app:progress="500"
app:increase="6.0"[水波涨幅]
app:upspeed="3"[上涨速度]
app:waterspeed="8"[移动速度]
app:strokesize="4dp"
app:textsize="20dp"

五、后记

代码已经上传github,欢迎有兴趣的朋友去看看。

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