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

Android仿水波纹流量球进度条控制器

程序员文章站 2024-02-29 19:45:52
仿水波纹流球进度条控制器,android实现高端大气的主流特效,供大家参考,具体内容如下 效果图: circleview 这里主要是实现中心圆以及水波特效...

仿水波纹流球进度条控制器,android实现高端大气的主流特效,供大家参考,具体内容如下

效果图:

Android仿水波纹流量球进度条控制器

circleview

这里主要是实现中心圆以及水波特效

package com.lgl.circleview;

import android.content.context;
import android.graphics.canvas;
import android.graphics.color;
import android.graphics.paint;
import android.graphics.path;
import android.graphics.rectf;
import android.os.handler;
import android.os.parcel;
import android.os.parcelable;
import android.util.attributeset;
import android.view.view;
import android.widget.progressbar;

/**
 * 水波圆
 * 
 * @author lgl
 * 
 */
public class circleview extends view {

 private context mcontext;

 private int mscreenwidth;
 private int mscreenheight;

 private paint mringpaint;
 private paint mcirclepaint;
 private paint mwavepaint;
 private paint linepaint;
 private paint flowpaint;
 private paint leftpaint;

 private int mringstrokewidth = 15;
 private int mcirclestrokewidth = 2;
 private int mlinestrokewidth = 1;

 private int mcirclecolor = color.white;
 private int mringcolor = color.white;
 private int mwavecolor = color.white;

 private handler mhandler;
 private long c = 0l;
 private boolean mstarted = false;
 private final float f = 0.033f;
 private int malpha = 50;// 透明度
 private float mamplitude = 10.0f; // 振幅
 private float mwaterlevel = 0.5f;// 水高(0~1)
 private path mpath;

 // 绘制文字显示在圆形中间,只是我没有设置,我觉得写在布局上也挺好的
 private string flownum = "";
 private string flowleft = "还剩余";

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

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

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

 public void setmwaterlevel(float mwaterlevel) {
  this.mwaterlevel = mwaterlevel;
 }

 private void init(context context) {
  mringpaint = new paint();
  mringpaint.setcolor(mringcolor);
  mringpaint.setalpha(50);
  mringpaint.setstyle(paint.style.stroke);
  mringpaint.setantialias(true);
  mringpaint.setstrokewidth(mringstrokewidth);

  mcirclepaint = new paint();
  mcirclepaint.setcolor(mcirclecolor);
  mcirclepaint.setstyle(paint.style.stroke);
  mcirclepaint.setantialias(true);
  mcirclepaint.setstrokewidth(mcirclestrokewidth);

  linepaint = new paint();
  linepaint.setcolor(mcirclecolor);
  linepaint.setstyle(paint.style.stroke);
  linepaint.setantialias(true);
  linepaint.setstrokewidth(mlinestrokewidth);

  flowpaint = new paint();
  flowpaint.setcolor(mcirclecolor);
  flowpaint.setstyle(paint.style.fill);
  flowpaint.setantialias(true);
  flowpaint.settextsize(36);

  leftpaint = new paint();
  leftpaint.setcolor(mcirclecolor);
  leftpaint.setstyle(paint.style.fill);
  leftpaint.setantialias(true);
  leftpaint.settextsize(36);

  mwavepaint = new paint();
  mwavepaint.setstrokewidth(1.0f);
  mwavepaint.setcolor(mwavecolor);
  mwavepaint.setalpha(malpha);
  mpath = new path();

  mhandler = new handler() {
   @override
   public void handlemessage(android.os.message msg) {
    if (msg.what == 0) {
     invalidate();
     if (mstarted) {
      // 不断发消息给自己,使自己不断被重绘
      mhandler.sendemptymessagedelayed(0, 60l);
     }
    }
   }
  };
 }

 @override
 protected void onmeasure(int widthmeasurespec, int heightmeasurespec) {
  int width = measure(widthmeasurespec, true);
  int height = measure(heightmeasurespec, false);
  if (width < height) {
   setmeasureddimension(width, width);
  } else {
   setmeasureddimension(height, height);
  }

 }

 /**
  * @category 测量
  * @param measurespec
  * @param iswidth
  * @return
  */
 private int measure(int measurespec, boolean iswidth) {
  int result;
  int mode = measurespec.getmode(measurespec);
  int size = measurespec.getsize(measurespec);
  int padding = iswidth ? getpaddingleft() + getpaddingright()
    : getpaddingtop() + getpaddingbottom();
  if (mode == measurespec.exactly) {
   result = size;
  } else {
   result = iswidth ? getsuggestedminimumwidth()
     : getsuggestedminimumheight();
   result += padding;
   if (mode == measurespec.at_most) {
    if (iswidth) {
     result = math.max(result, size);
    } else {
     result = math.min(result, size);
    }
   }
  }
  return result;
 }

 @override
 protected void onsizechanged(int w, int h, int oldw, int oldh) {
  // todo auto-generated method stub
  super.onsizechanged(w, h, oldw, oldh);
  mscreenwidth = w;
  mscreenheight = h;
 }

 @override
 protected void ondraw(canvas canvas) {
  // todo auto-generated method stub
  super.ondraw(canvas);
  // 得到控件的宽高
  int width = getwidth();
  int height = getheight();
  setbackgroundcolor(mcontext.getresources().getcolor(r.color.main_bg));
  // 计算当前油量线和水平中线的距离
  float centeroffset = math.abs(mscreenwidth / 2 * mwaterlevel
    - mscreenwidth / 4);
  // 计算油量线和与水平中线的角度
  float horiangle = (float) (math.asin(centeroffset / (mscreenwidth / 4)) * 180 / math.pi);
  // 扇形的起始角度和扫过角度
  float startangle, sweepangle;
  if (mwaterlevel > 0.5f) {
   startangle = 360f - horiangle;
   sweepangle = 180f + 2 * horiangle;
  } else {
   startangle = horiangle;
   sweepangle = 180f - 2 * horiangle;
  }

  canvas.drawline(mscreenwidth * 3 / 8, mscreenheight * 5 / 8,
    mscreenwidth * 5 / 8, mscreenheight * 5 / 8, linepaint);

  float num = flowpaint.measuretext(flownum);
  canvas.drawtext(flownum, mscreenwidth * 4 / 8 - num / 2,
    mscreenheight * 4 / 8, flowpaint);
  float left = leftpaint.measuretext(flowleft);
  canvas.drawtext(flowleft, mscreenwidth * 4 / 8 - left / 2,
    mscreenheight * 3 / 8, leftpaint);

  // 如果未开始(未调用startwave方法),绘制一个扇形
  if ((!mstarted) || (mscreenwidth == 0) || (mscreenheight == 0)) {
   // 绘制,即水面静止时的高度
   rectf oval = new rectf(mscreenwidth / 4, mscreenheight / 4,
     mscreenwidth * 3 / 4, mscreenheight * 3 / 4);
   canvas.drawarc(oval, startangle, sweepangle, false, mwavepaint);
   return;
  }
  // 绘制,即水面静止时的高度
  // 绘制,即水面静止时的高度
  rectf oval = new rectf(mscreenwidth / 4, mscreenheight / 4,
    mscreenwidth * 3 / 4, mscreenheight * 3 / 4);
  canvas.drawarc(oval, startangle, sweepangle, false, mwavepaint);

  if (this.c >= 8388607l) {
   this.c = 0l;
  }
  // 每次ondraw时c都会自增
  c = (1l + c);
  float f1 = mscreenheight * (1.0f - (0.25f + mwaterlevel / 2))
    - mamplitude;
  // 当前油量线的长度
  float wavewidth = (float) math.sqrt(mscreenwidth * mscreenwidth / 16
    - centeroffset * centeroffset);
  // 与圆半径的偏移量
  float offsetwidth = mscreenwidth / 4 - wavewidth;

  int top = (int) (f1 + mamplitude);
  mpath.reset();
  // 起始振动x坐标,结束振动x坐标
  int startx, endx;
  if (mwaterlevel > 0.50f) {
   startx = (int) (mscreenwidth / 4 + offsetwidth);
   endx = (int) (mscreenwidth / 2 + mscreenwidth / 4 - offsetwidth);
  } else {
   startx = (int) (mscreenwidth / 4 + offsetwidth - mamplitude);
   endx = (int) (mscreenwidth / 2 + mscreenwidth / 4 - offsetwidth + mamplitude);
  }
  // 波浪效果
  while (startx < endx) {
   int starty = (int) (f1 - mamplitude
     * math.sin(math.pi
       * (2.0f * (startx + this.c * width * this.f))
       / width));
   canvas.drawline(startx, starty, startx, top, mwavepaint);
   startx++;
  }
  canvas.drawcircle(mscreenwidth / 2, mscreenheight / 2, mscreenwidth / 4
    + mringstrokewidth / 2, mringpaint);

  canvas.drawcircle(mscreenwidth / 2, mscreenheight / 2,
    mscreenwidth / 4, mcirclepaint);
  canvas.restore();
 }

 @override
 public parcelable onsaveinstancestate() {
  parcelable superstate = super.onsaveinstancestate();
  savedstate ss = new savedstate(superstate);
  ss.progress = (int) c;
  return ss;
 }

 @override
 public void onrestoreinstancestate(parcelable state) {
  savedstate ss = (savedstate) state;
  super.onrestoreinstancestate(ss.getsuperstate());
  c = ss.progress;
 }

 @override
 protected void onattachedtowindow() {
  super.onattachedtowindow();
  // 关闭硬件加速,防止异常unsupported operation exception
  this.setlayertype(view.layer_type_software, null);
 }

 @override
 protected void ondetachedfromwindow() {
  super.ondetachedfromwindow();
 }

 /**
  * @category 开始波动
  */
 public void startwave() {
  if (!mstarted) {
   this.c = 0l;
   mstarted = true;
   this.mhandler.sendemptymessage(0);
  }
 }

 /**
  * @category 停止波动
  */
 public void stopwave() {
  if (mstarted) {
   this.c = 0l;
   mstarted = false;
   this.mhandler.removemessages(0);
  }
 }

 /**
  * @category 保存状态
  */
 static class savedstate extends basesavedstate {
  int progress;

  /**
   * constructor called from {@link progressbar#onsaveinstancestate()}
   */
  savedstate(parcelable superstate) {
   super(superstate);
  }

  /**
   * constructor called from {@link #creator}
   */
  private savedstate(parcel in) {
   super(in);
   progress = in.readint();
  }

  @override
  public void writetoparcel(parcel out, int flags) {
   super.writetoparcel(out, flags);
   out.writeint(progress);
  }

  public static final parcelable.creator<savedstate> creator = new parcelable.creator<savedstate>() {
   public savedstate createfromparcel(parcel in) {
    return new savedstate(in);
   }

   public savedstate[] newarray(int size) {
    return new savedstate[size];
   }
  };
 }

}

我们运行一下

Android仿水波纹流量球进度条控制器

其实他是十分的空旷的,所以也值得我们去定制,我们在中间加个流量显示,再加个进度条
activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<relativelayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:background="@color/main_bg" >

 <textview
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_alignparenttop="true"
  android:layout_centerhorizontal="true"
  android:layout_margintop="10dp"
  android:text="流量"
  android:textcolor="@android:color/white"
  android:textsize="18sp" />

 <com.lgl.circleview.circleview
  android:id="@+id/wave_view"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:layout_centerinparent="true" />

 <textview
  android:id="@+id/power"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:layout_centerinparent="true"
  android:textcolor="@android:color/white" />

 <seekbar
  android:id="@+id/seekbar"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:layout_alignparentbottom="true"
  android:layout_marginbottom="150dp" />

</relativelayout>

我们要实现这个,就要调用它的初始化以及start方法

 mcircleview = (circleview) findviewbyid(r.id.wave_view);
  // 设置多高,float,0.1-1f
  mcircleview.setmwaterlevel(0.1f);
  // 开始执行
  mcircleview.startwave();

别忘了activity销毁的时候把它回收哦
@override
 protected void ondestroy() {
  // todo auto-generated method stub
  mcircleview.stopwave();
  mcircleview = null;
  super.ondestroy();
 }

我们再运行一遍

Android仿水波纹流量球进度条控制器

但是我们要怎么让水波纹随着进度条一起上升下降尼?,这里我们就要用到我们刚才写的seekbar了,我们实现它的

setonseekbarchangelistener来监听,这样我们就要复写他的三个方法,这里我们只要用到一个
public void onprogresschanged(seekbar seekbar, int progress,
     boolean fromuser) {
    //跟随进度条滚动
    mcircleview.setmwaterlevel((float) progress / 100);
    }

这里,我们要这样算的,我们设置高度的单位是float,也就是从0-1f,而我们的进度是int progress,从0-100,我们就要用(float) progress / 100)并且强转来得到单位,好了,我们现在水波纹的高度就是随着我们的进度条一起变化了,我们再来运行一下

Android仿水波纹流量球进度条控制器

好的,这样的话,我们就只剩下一个了,就是让大小随着我们的进度条变化了,这里我们因为更新ui不能再主线程中操作,所以我们需要用到我们的老伙计handler了,但是用到handler还不够,我们的进度条数值也是在内部类里面,所以这里我们需要用到handler来传值了,这里我们用的是bundle,我们还是在onprogresschanged方法中操作了

 //创建一个消息
    message message = new message();
    bundle bundle = new bundle();
    //put一个int值
    bundle.putint("progress", progress);
    //装载
    message.setdata(bundle);
    //发送消息
    handler.sendmessage(message);
    //创建表示
    message.what = 1;

消息发送过去了,我们就在前面写个handler去接收就是了

 private handler handler = new handler() {
  public void handlemessage(android.os.message msg) {
   if (msg.what == 1) {
    int num = msg.getdata().getint("progress");
    log.i("num", num + "");
    power.settext((float) num / 100 * max + "m/" + max + "m");
   }
  }
 };

这里的计算公式尼,是当前的数值/100得到百分比再去*最大值。我们现在可以完整的运行一下了,其实和最上面运行的图片是一样的

Android仿水波纹流量球进度条控制器

mainactivity

package com.lgl.circleview;

import android.app.activity;
import android.os.bundle;
import android.os.handler;
import android.os.message;
import android.util.log;
import android.widget.seekbar;
import android.widget.textview;

public class mainactivity extends activity {

 private circleview mcircleview;
 private seekbar mseekbar;
 private textview power;
 private int max = 1024;
 private int min = 102;

 private handler handler = new handler() {
 public void handlemessage(android.os.message msg) {
  if (msg.what == 1) {
  int num = msg.getdata().getint("progress");
  log.i("num", num + "");
  power.settext((float) num / 100 * max + "m/" + max + "m");
  }
 }
 };

 @override
 protected void oncreate(bundle savedinstancestate) {
 super.oncreate(savedinstancestate);
 getactionbar().hide();
 setcontentview(r.layout.activity_main);

 power = (textview) findviewbyid(r.id.power);
 power.settext(min + "m/" + max + "m");

 mcircleview = (circleview) findviewbyid(r.id.wave_view);
 // 设置多高,float,0.1-1f
 mcircleview.setmwaterlevel(0.1f);
 // 开始执行
 mcircleview.startwave();

 mseekbar = (seekbar) findviewbyid(r.id.seekbar);
 mseekbar.setonseekbarchangelistener(new seekbar.onseekbarchangelistener() {
  @override
  public void onprogresschanged(seekbar seekbar, int progress,
   boolean fromuser) {
  mcircleview.setmwaterlevel((float) progress / 100);
  // 创建一个消息
  message message = new message();
  bundle bundle = new bundle();
  // put一个int值
  bundle.putint("progress", progress);
  // 装载
  message.setdata(bundle);
  // 发送消息
  handler.sendmessage(message);
  // 创建表示
  message.what = 1;
  }

  @override
  public void onstarttrackingtouch(seekbar seekbar) {

  }

  @override
  public void onstoptrackingtouch(seekbar seekbar) {

  }
 });
 }

 @override
 protected void ondestroy() {
 // todo auto-generated method stub
 mcircleview.stopwave();
 mcircleview = null;
 super.ondestroy();
 }
}

代码下载:android仿水波纹流量球进度条

以上就是本文的全部内容,希望对大家学习android软件编程有所帮助。