Android仿水波纹流量球进度条控制器
程序员文章站
2024-02-29 19:45:52
仿水波纹流球进度条控制器,android实现高端大气的主流特效,供大家参考,具体内容如下
效果图:
circleview
这里主要是实现中心圆以及水波特效...
仿水波纹流球进度条控制器,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]; } }; } }
我们运行一下
其实他是十分的空旷的,所以也值得我们去定制,我们在中间加个流量显示,再加个进度条
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(); }
我们再运行一遍
但是我们要怎么让水波纹随着进度条一起上升下降尼?,这里我们就要用到我们刚才写的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)并且强转来得到单位,好了,我们现在水波纹的高度就是随着我们的进度条一起变化了,我们再来运行一下
好的,这样的话,我们就只剩下一个了,就是让大小随着我们的进度条变化了,这里我们因为更新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得到百分比再去*最大值。我们现在可以完整的运行一下了,其实和最上面运行的图片是一样的
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软件编程有所帮助。
推荐阅读