当前位置: 移动技术网 > 移动技术>移动开发>Android > android球形水波百分比控件代码

android球形水波百分比控件代码

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

本文主要介绍的是一个球形水波的百分比控件,市面上有各种形形色色的百分比控件,我一直觉得水波是最炫的,ui给了我这个机会,然而网上搜了一大堆,不是太复杂,代码太多(反正我是调不出效果来),就是有瑕疵的,所以只好自己写了,这里开源出来,方便大家。有什么问题或者建议大家留言指出。

先看效果,这里动态图不好截取,就贴张静态的

对于水波百分比控件实现方法有如下几种

  • - 画好水波形状的bitmap,利用属性动画进行平移
  • - 利用曲线精确绘制目标水波
  • - 利用大范围曲线与容器做交集

第一种比较烦,网上有这种思路实现的,代码量比较庞大。bitmap移动时要注意的问题很多,一不小心就bug一堆了。第二种代码量小,但需要几何功底。很丢脸的说我算了好久。才算出公式(年代久远,都忘了),不过这种方法计算量大,绘制时遍历的点少。第三种方法,代码量极少,计算量几乎没有,遍历的点是第二种方法的两倍以上。考虑到遍历的消耗和计算的复杂度,选择第三种。

这里我们选择正弦曲线和圆做交集。

 for (int i = left; i < length; i++) {
        int x = i;
        int y = (int) (math.sin(math.toradians(x + mtranx) / 2) * mradius / 4);
        path2.lineto(x, mh + y);
      }

sin函数,x横坐标,y纵坐标,mtranx每次偏移量, 波形起伏mradius / 4,

核心代码

利用圆的path与我们之前绘制的曲线做交集

path pc = new path();
      pc.addcircle(mcentrepoint.x, mcentrepoint.y, mradius, path.direction.ccw);
      canvas.clippath(pc, region.op.intersect);
      canvas.drawpath(path2, mwavepaint);
      canvas.restore();

水位上升和水波起伏

while (isdraw) {
        if (mwaterlevel > mnowheight) {
          mnowheight = mnowheight + mupspeed;
        }
        if (mstart) {
          if (mtranx > mradius) {
            mtranx = 0;
          }
          mtranx = mtranx - mwavespeed;
        }
        drawui();
      }

这里由于动画效果比较细腻,更新ui界面比较平凡,所以我们采用surfaceview来实现(用view实现发现有卡顿,影响体验)

完整代码

就一个waveview类直接布局中引用

注释写的应该算比较清楚了。有什么疑问的可以留言

package com.aibaide.test;


import android.content.context;
import android.graphics.canvas;
import android.graphics.color;
import android.graphics.paint;
import android.graphics.path;
import android.graphics.pixelformat;
import android.graphics.point;
import android.graphics.region;
import android.util.attributeset;
import android.view.surfaceholder;
import android.view.surfaceview;

/**
 * gengqiquan
 * 2016年6月2日16:16:48
 * 水波显示百分比控件
 */
public class waveview extends surfaceview implements surfaceholder.callback {

  point mcentrepoint;
  int mnowheight = 0;//当前水位
  int mradius = 0;
  boolean mstart = false;//是否开始
  float mtextsise = 60;//文字大小
  context mcontext;
  int mtranx = 0;//水波平移量
  private paint mcirclepaint;
  private paint moutcirclepaint;
  private paint mwavepaint;
  private paint mtextpaint;
  private surfaceholder holder;
  private renderthread renderthread;
  private boolean isdraw = false;// 控制绘制的开关
  private int mcirclecolor = color.parsecolor("#ff6600");//背景内圆颜色
  private int moutcirclecolor = color.parsecolor("#f5e6dc");//背景外圆颜色
  private int mwavecolor = color.parsecolor("#ff944d");//水波颜色
  private int mwaterlevel;// 水目标高度
  private int flownum = 60;//水目标占百分比这里是整数。
  private int mwavespeed = 5;//水波起伏速度
  private int mupspeed = 2;//水面上升速度

  /**
   * @param context
   */
  public waveview(context context) {
    super(context);
    // todo auto-generated constructor stub
    mcontext = context;
    init(mcontext);
  }

  /**
   * @param context
   * @param attrs
   */
  public waveview(context context, attributeset attrs) {
    super(context, attrs);
    // todo auto-generated constructor stub
    mcontext = context;
    init(mcontext);
  }

  /**
   * @param context
   * @param attrs
   * @param defstyleattr
   */
  public waveview(context context, attributeset attrs, int defstyleattr) {
    super(context, attrs, defstyleattr);
    // todo auto-generated constructor stub
    mcontext = context;
    init(mcontext);
  }

  private void init(context context) {
    mcontext = context;
    setzorderontop(true);
    holder = this.getholder();
    holder.addcallback(this);
    holder.setformat(pixelformat.translucent);
    renderthread = new renderthread();

    mcirclepaint = new paint();
    mcirclepaint.setcolor(mcirclecolor);
    mcirclepaint.setstyle(paint.style.fill);
    mcirclepaint.setantialias(true);

    moutcirclepaint = new paint();
    moutcirclepaint.setcolor(moutcirclecolor);
    moutcirclepaint.setstyle(paint.style.fill);
    moutcirclepaint.setantialias(true);

    mwavepaint = new paint();
    mwavepaint.setstrokewidth(1.0f);
    mwavepaint.setcolor(mwavecolor);
    mwavepaint.setstyle(paint.style.fill);
    mwavepaint.setantialias(true);

    mtextpaint = new paint();
    mtextpaint.setstrokewidth(1.0f);
    mtextpaint.setcolor(color.white);
    mtextpaint.settextsize(mtextsise);
    mtextpaint.settextalign(paint.align.center);
    mtextpaint.setstyle(paint.style.fill);
    mtextpaint.setantialias(true);


  }


  @override
  public void surfacechanged(surfaceholder holder, int format, int width, int height) {
    mradius = (int) (0.5 * width * 0.92);
    mcentrepoint = new point(width / 2, height / 2);
    mwaterlevel = (int) (2 * mradius * flownum / 100f);//算出目标水位高度
  }

  @override
  public void surfacecreated(surfaceholder holder) {
    isdraw = true;
    if (renderthread != null && !renderthread.isalive())
      renderthread.start();

  }

  @override
  public void surfacedestroyed(surfaceholder holder) {
    isdraw = false;

  }

  /**
   * 绘制界面的线程
   *
   * @author administrator
   */
  private class renderthread extends thread {
    @override
    public void run() {
      // 不停绘制界面,这里是异步绘制,不采用外部通知开启绘制的方式,水波根据数据更新才会开始增长
      while (isdraw) {
        if (mwaterlevel > mnowheight) {
          mnowheight = mnowheight + mupspeed;
        }
        if (mstart) {
          if (mtranx > mradius) {
            mtranx = 0;
          }
          mtranx = mtranx - mwavespeed;
        }
        drawui();
      }
      super.run();
    }
  }

  /**
   * 界面绘制
   */
  public void drawui() {
    canvas canvas = holder.lockcanvas();
    try {
      drawcanvas(canvas);
    } catch (exception e) {
      e.printstacktrace();
    } finally {
      if (canvas != null)
        holder.unlockcanvasandpost(canvas);
    }
  }

  private void drawcanvas(canvas canvas) {
    //画背景圆圈
    canvas.drawcircle(mcentrepoint.x, mcentrepoint.y, mradius / 0.92f, moutcirclepaint);
    canvas.drawcircle(mcentrepoint.x, mcentrepoint.y, mradius, mcirclepaint);
    if (mstart) {
      //计算正弦曲线的路径
      int mh = mcentrepoint.y + mradius - mnowheight;
      int left = - mradius / 2;
      int length = 4 * mradius;
      path path2 = new path();
      path2.moveto(left, mh);

      for (int i = left; i < length; i++) {
        int x = i;
        int y = (int) (math.sin(math.toradians(x + mtranx) / 2) * mradius / 4);
        path2.lineto(x, mh + y);
      }
      path2.lineto(length, mh);
      path2.lineto(length, mcentrepoint.y + mradius);
      path2.lineto(0, mcentrepoint.y + mradius);
      path2.lineto(0, mh);

      canvas.save();
      //这里与圆形取交集,除去正弦曲线多画的部分
      path pc = new path();
      pc.addcircle(mcentrepoint.x, mcentrepoint.y, mradius, path.direction.ccw);
      canvas.clippath(pc, region.op.intersect);
      canvas.drawpath(path2, mwavepaint);
      canvas.restore();
      //绘制文字
      canvas.drawtext(flownum + "%", mcentrepoint.x, mcentrepoint.y, mtextpaint);
    }
  }

  public void setflownum(int num) {
    flownum = num;
    mstart = true;
  }

  public void settextsise(float s) {
    mtextsise = s;
    mtextpaint.settextsize(s);
  }

  //设置水波起伏速度
  public void setwavespeed(int speed) {
    mwavespeed = speed;
  }

  //设置水面上升速度
  public void setupspeed(int speed) {
    mupspeed = speed;
  }

  public void setcolor(int wavecolor, int circlecolor, int outcirclecolor) {
    mwavecolor = wavecolor;
    mcirclecolor = circlecolor;
    moutcirclecolor = outcirclecolor;
    mwavepaint.setcolor(mwavecolor);
    mcirclepaint.setcolor(mcirclecolor);
    moutcirclepaint.setcolor(moutcirclecolor);
  }
//精确算法,每次正弦曲线从曲线与圆的交集处开始
//  private int getx(double h) {
//    int x = 0;
//    int r = mradius;
//    if (h < r) {
//      double t = 2 * r * h - h * h;
//      x = (int) (r - math.abs(math.sqrt(t)));
//    } else {
//      double t = -2 * r * h + h * h;
//      x = (int) (r - math.abs(math.sqrt(t)));
//    }
//    return x;
//  }
}

最后奉上本文的源码:

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网