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

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

程序员文章站 2024-03-02 19:19:22
本文主要介绍的是一个球形水波的百分比控件,市面上有各种形形色色的百分比控件,我一直觉得水波是最炫的,ui给了我这个机会,然而网上搜了一大堆,不是太复杂,代码太多(反正我是调...

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

先看效果,这里动态图不好截取,就贴张静态的
android球形水波百分比控件代码

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

  • - 画好水波形状的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;
//  }
}

最后奉上本文的源码:源码下载

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