您的位置:首页 > 移动开发 > Android开发

Android自定义控件NumberCircleProgressBar(圆形进度条)的实现

2014-09-06 17:32 489 查看
最近在Github上看到了daimajia写的一个开源组件NumberProgressBar觉得非常好,故而在其基础上进行了一些延伸与扩展,编写了一个NumberCircleProgressBar(即圆形的进度条),并且分为两种模式,我称之为rotate模式和rising_water模式。

PS:也许本文介绍的方法不是最优(比如游戏开发中可能只需要调用一个方法即可完成),也可能会有纰漏,所以请读者海涵!

NumberCircleProgressBar的样图如下:

Rotate模式





Rising_Water模式







组件属性



对于两种不同的模式,如上图所示,均有以下属性:

TheCircle

circle_radius
fill_mode(name="rotate" value="0",name="rising_water" value="1" )

The reached area and unreachedarea:

color
height

The text area:

color
text size
visibility

The bar:

max progress
current progress

如何使用

这个组件很小,就没必要制作成库了,所以使用者copy一下相关目录下文件即可:

1. 将src/NumberCircleProgressBar.java文件拷贝到相应目录;

2. 将res/values/attrs.xml中NumberCircleProgressBar的属性定义拷贝到相应目录;

在布局文件中定义NumberCircleProgressBar
<com.cjl.numbercircleprogressbar.NumberCircleProgressBar
android:id="@+id/numbercircleprogress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:padding="10dp"
custom:max="100"
custom:progress="0"
custom:progress_circle_radius="50dp"
custom:progress_fill_mode="rotate"
custom:progress_reached_color="#3498DB"
custom:progress_text_color="@android:color/black"
custom:progress_text_size="15sp"
custom:progress_text_visibility="visible"
custom:progress_unreached_color="#CCCCCC" />


在style.xml中定义NumberCircleProgressBar属性

<style name="NumberCircleProgressBar_Default">
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_width">match_parent</item>
<item name="max">100</item>
<item name="progress">10</item>
<item name="progress_unreached_color">#CCCCCC</item>
<item name="progress_reached_color">#3498DB</item>
<item name="progress_circle_radius">20dp</item>
<item name="progress_text_size">10sp</item>
<item name="progress_text_color">#000000</item>
<item name="progress_fill_mode">0</item>
</style>


在布局文件中使用style
<com.cjl.numbercircleprogressbar.NumberCircleProgressBar
style="@style/NumberCircleProgressBar_Default"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
anroid:padding="10dp" />


[b]java代码中使用样例

[/b]
public void setTheNumberProgressBar() {

final NumberCircleProgressBar bnp = (NumberCircleProgressBar) findViewById(R.id.numbercircleprogress_bar);
timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
if (!isFinish) {
bnp.incrementProgressBy(2);
if (bnp.isFinished()) {
isFinish = false;
}
}
}
});
}
}, 1000, 100);
}



如何实现自定义组件

关键是在view的OnDraw方法中进行重绘。

[b]Mode Rotate 实现方式

1.使用unreachedarea的颜色绘制Circle,作为底层;
canvas.drawCircle(centerX, centerY,mCircleRadius, mCirclePaint);

2.使用reacherarea的颜色绘制扇形,作为中间层;
canvas.drawArc(mCircleRectF,DEFAULT_INITIAL_ANGLE, getProgress() * 360 / getMax(),true, mSectorPaint);

3.使用textarea的颜色绘制文字,作为顶层;
canvas.drawText(mCurrentDrawText,mDrawTextStart, mDrawTextEnd, mTextPaint);


Mode Rising Water实现方法

这里必须要说明一下如何绘制扇形的截取部分,请看下图:



为了绘制图中的蓝色部分,我们需要先绘制蓝色部分对应的扇形,其次再绘制三角形灰色部分覆盖蓝色扇形部分(或者绘制蓝色三角形补全扇形部分)。所以我们必须要知道角α,进而求出三角形中除圆心坐标外的两点。

如何求α?
设p为已知的百分比,则p∈[0,1],




联立方程可以得到



得到方程



这里遇到了难题,如何求超越方程的解?
一开始我在这卡住了,在网上搜了半天,实在没找到这类超越方程的解法。后来突然想到模拟求解啊,这不就是计算机思维的解决之道吗?于是乎下载Mathematic软件来进行求解:



得到了p为[0%,100%]之间的步长为1%的对应角度α的数组:
PERCENT_TO_ARC = { 0, 0.364413d, 0.4616d,
0.530831d, 0.586699d, 0.634474d, 0.676734d, 0.714958d, 0.750081d,
0.782736d, 0.813377d, 0.842337d, 0.869872d, 0.896184d, 0.921432d,
0.945747d, 0.969237d, 0.991993d, 1.01409d, 1.0356d, 1.05657d,
1.07706d, 1.0971d, 1.11674d, 1.13601d, 1.15494d, 1.17356d,
1.19189d, 1.20996d, 1.22779d, 1.24539d, 1.26279d, 1.27999d,
1.29702d, 1.31389d, 1.33061d, 1.3472d, 1.36366d, 1.38d, 1.39625d,
1.4124d, 1.42847d, 1.44446d, 1.46039d, 1.47627d, 1.49209d,
1.50788d, 1.52364d, 1.53937d, 1.55509d, 0.5 * Math.PI, 1.58651d,
1.60222d, 1.61796d, 1.63371d, 1.6495d, 1.66533d, 1.6812d, 1.69713d,
1.71313d, 1.72919d, 1.74535d, 1.76159d, 1.77794d, 1.7944d,
1.81098d, 1.8277d, 1.84457d, 1.8616d, 1.8788d, 1.8962d, 1.9138d,
1.93163d, 1.9497d, 1.96803d, 1.98665d, 2.00558d, 2.02485d,
2.04449d, 2.06454d, 2.08502d, 2.10599d, 2.1275d, 2.1496d, 2.17236d,
2.19585d, 2.22016d, 2.24541d, 2.27172d, 2.29926d, 2.32822d,
2.35886d, 2.39151d, 2.42663d, 2.46486d, 2.50712d, 2.55489d,
2.61076d, 2.67999d, 2.77718d, Math.PI };


得到了角度α,那么成功近在咫尺了:
1. 使用unreachedarea的颜色绘制Circle,作为底层;
2. 使用reacherarea的颜色绘制扇形,作为中间层;
3. 当percent∈[0,50%]时,使用unreached area的颜色绘制三角形覆盖扇形相应位置;
当percent∈[50%,100%]时,使用reached area的颜色绘制三角形填充扇形相应位置;
1. 使用textarea的颜色绘制文字,作为顶层;

大功告成,但此时观察Demo程序,发现还是有点瑕疵。
三角形没有完全覆盖扇形的那部分面积,留下了两条边线隐约可以看到底层扇形的颜色,而且在使用Visio绘制文档中图例时也出现了这种情况!!
查找了半天,实在没发现哪有什么错误的地方。最终只得使用一点实际的办法了——以一定粗度的实线绘制三角形的两条边,覆盖透出的颜色。这也许不是正确的方案,但解决了问题,如果读者有更好的办法或者知道此bug的出处,希望告知!
这里要赞一下腾讯的应用宝,手机没有root,无法使用截屏软件来制作gif,而应用宝里有动态截屏制作gif,有点不足的地方就是需要手动点,如果有设帧率的地方就更好了!
工程源代码

It’s Over!

[/b]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: