一、效果图
本控件已上传github,欢迎star和fork,项目地址:circlewaterwaveview
二、设计思路
观察效果图,可以看出,该自定义控件由三个部分构成:外圆、内圆、正弦曲线。他们的关系如下图:
因为控件是动态的,所以我们需要一个线程去不停地绘制,所以我选择了surfaceview来作为该控件地父类。该控件地核心是如何去绘制波浪,我采用如下的思路来进行内圆下部地绘制。利用内圆与正弦曲线地交集,来绘制。
核心代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
/** * 绘制图像 * * @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(); //恢复画布状态 } } |
三、性能优化
绘制线程如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
/** * 绘制界面的线程 * * @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添加监听,来控制绘制线程。当控件被隐藏不在前台显示时,自动结束绘制线程,当控件显示在前台时,再次开启绘制。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
@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文件中,直接以属性赋值的操作。
1
2
3
4
5
6
7
8
9
10
11
12
|
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,欢迎有兴趣的朋友去看看。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/lx578111527/article/details/52797947