**一、概述**
在上一篇博文中,我们给大家介绍了Android自定义控件系列的基础篇。链接: http://www.cnblogs.com/jerehedu/p/4360066.html
这一篇博文中,我们将在基础篇的基础上,再通过重写ondraw()方法和自定义属性实现圆形进度条,效果如图所示:


**二、实现步骤**
1、 编写自定义组件MyCircleProgress扩展View
<span class="keyword">public</span> <span class="class"><span class="keyword">class</span></span><span class="class"> <span class="title">MyCircleProgress</span> <span class="keyword">extends</span> <span class="title">View</span> {</span>
…
}
2、 在MyCircleProgress类中,定制属性
<span class="keyword">public</span> <span class="keyword">int</span> progress = <span class="number"></span>;<span class="comment">//</span><span class="comment">进度实际值,当前进度</span>
<span class="javadoc">/**</span><span class="javadoc">
* 自定义控件属性,可灵活的设置圆形进度条的大小、颜色、类型等
*/</span>
<span class="keyword">private</span> <span class="keyword">int</span> mR;<span class="comment">//</span><span class="comment">圆半径,决定圆大小</span>
<span class="keyword">private</span> <span class="keyword">int</span> bgColor;<span class="comment">//</span><span class="comment">圆或弧的背景颜色</span>
<span class="keyword">private</span> <span class="keyword">int</span> fgColor;<span class="comment">//</span><span class="comment">圆或弧的前景颜色,即绘制时的颜色</span>
<span class="keyword">private</span> <span class="keyword">int</span> drawStyle; <span class="comment">//</span><span class="comment">绘制类型 FILL画圆形进度条,STROKE绘制弧形进度条</span>
<span class="keyword">private</span> <span class="keyword">int</span> strokeWidth;<span class="comment">//</span><span class="comment">STROKE绘制弧形的弧线的宽度</span>
<span class="keyword">private</span> <span class="keyword">int</span> max;<span class="comment">//</span><span class="comment">最大值,设置进度的最大值</span>
<span class="javadoc">/**</span><span class="javadoc">
* 设置进度,此为线程安全控件,由于考虑多线的问题,需要同步
*/</span>
<span class="keyword">public</span> <span class="keyword">synchronized</span> <span class="keyword">void</span> setProgress(<span class="keyword">int</span> progress) {
<span class="keyword">if</span>(progress<<span class="number"></span>){
progress=<span class="number"></span>;
}<span class="keyword">else</span> <span class="keyword">if</span>(progress>max){
progress=max;
}<span class="keyword">else</span>{
<span class="keyword">this</span>.progress = progress;
}
}
<span class="keyword">public</span> <span class="keyword">int</span> getMax() {
<span class="keyword">return</span> max; }
3、 为定制的属性编写attrs.xml资源,该资源文件放在res/values目录下,内容如下:
<span class="pi"><?</span><span class="pi">xml version="1.0" encoding="utf-8"?></span>
<span class="tag"><</span><span class="tag"><span class="title">resources</span>></span>
<span class="tag"><</span><span class="tag"><span class="title">declare-styleable</span> <span class="attribute">name</span>=<span class="value">"CircleProgressBar"</span>></span>
<span class="tag"><</span><span class="tag"><span class="title">attr</span> <span class="attribute">name</span>=<span class="value">"bgColor"</span> <span class="attribute">format</span>=<span class="value">"color"</span>/></span>
<span class="tag"><</span><span class="tag"><span class="title">attr</span> <span class="attribute">name</span>=<span class="value">"fgColor"</span> <span class="attribute">format</span>=<span class="value">"color"</span>/></span>
<span class="tag"><</span><span class="tag"><span class="title">attr</span> <span class="attribute">name</span>=<span class="value">"r"</span> <span class="attribute">format</span>=<span class="value">"integer"</span>/></span>
<span class="tag"><</span><span class="tag"><span class="title">attr</span> <span class="attribute">name</span>=<span class="value">"strokeWidth"</span> <span class="attribute">format</span>=<span class="value">"integer"</span>/></span>
<span class="tag"><</span><span class="tag"><span class="title">attr</span> <span class="attribute">name</span>=<span class="value">"drawStyle"</span>></span>
<span class="tag"><</span><span class="tag"><span class="title">enum</span> <span class="attribute">name</span>=<span class="value">"STROKE"</span> <span class="attribute">value</span>=<span class="value">"0"</span>></span><span class="tag"></</span><span class="tag"><span class="title">enum</span>></span>
<span class="tag"><</span><span class="tag"><span class="title">enum</span> <span class="attribute">name</span>=<span class="value">"FILL"</span> <span class="attribute">value</span>=<span class="value">"1"</span>></span><span class="tag"></</span><span class="tag"><span class="title">enum</span>></span>
<span class="tag"></</span><span class="tag"><span class="title">attr</span>></span>
<span class="tag"><</span><span class="tag"><span class="title">attr</span> <span class="attribute">name</span>=<span class="value">"max"</span> <span class="attribute">format</span>=<span class="value">"integer"</span>/></span>
<span class="tag"></</span><span class="tag"><span class="title">declare-styleable</span>></span>
<span class="tag"></</span><span class="tag"><span class="title">resources</span>></span>
4、 在MyCircleProgress类中定义构造函数,初始化属性
<span class="keyword">private</span> <span class="keyword">void</span> initProperty(AttributeSet attrs){
TypedArray tArray = context.obtainStyledAttributes(attrs, R.styleable.CircleProgressBar);
mR=tArray.getInteger(R.styleable.CircleProgressBar_r,<span class="number">10</span>);
bgColor=tArray.getColor(R.styleable.CircleProgressBar_bgColor, Color.GRAY);
fgColor=tArray.getColor(R.styleable.CircleProgressBar_fgColor, Color.RED);
drawStyle=tArray.getInt(R.styleable.CircleProgressBar_drawStyle, <span class="number"></span>);
strokeWidth=tArray.getInteger(R.styleable.CircleProgressBar_strokeWidth, <span class="number">10</span>);
max=tArray.getInteger(R.styleable.CircleProgressBar_max, <span class="number">100</span>);
}
<span class="keyword">public</span> MyCircleProgress(Context context, AttributeSet attrs) {
<span class="keyword">super</span>(context, attrs);
<span class="keyword">this</span>.context = context;
<span class="keyword">this</span>.paint = <span class="keyword">new</span> Paint();
<span class="keyword">this</span>.paint.setAntiAlias(<span class="keyword">true</span>); <span class="comment">//</span><span class="comment"> 消除锯齿</span>
<span class="keyword">this</span>.paint.setStyle(Style.STROKE); <span class="comment">//</span><span class="comment"> 绘制空心圆或 空心矩形</span>
initProperty(attrs);
}
5、 在MainActivity中布局文件中添加MyCircleProgress组件,如下所示
<span class="tag"><</span><span class="tag"><span class="title">RelativeLayout</span> <span class="attribute">xmlns:android</span>=<span class="value">"http://schemas.android.com/apk/res/android"</span>
<span class="attribute">xmlns:tools</span>=<span class="value">"http://schemas.android.com/tools"</span>
<span class="attribute">xmlns:app</span>=<span class="value">"http://schemas.android.com/apk/res/com.jereh.mydrawcircleprogress"</span>
<span class="attribute">android:layout_width</span>=<span class="value">"match_parent"</span>
<span class="attribute">android:layout_height</span>=<span class="value">"match_parent"</span>
<span class="attribute">android:paddingBottom</span>=<span class="value">"@dimen/activity_vertical_margin"</span>
<span class="attribute">android:paddingLeft</span>=<span class="value">"@dimen/activity_horizontal_margin"</span>
<span class="attribute">android:paddingRight</span>=<span class="value">"@dimen/activity_horizontal_margin"</span>
<span class="attribute">android:paddingTop</span>=<span class="value">"@dimen/activity_vertical_margin"</span>
<span class="attribute">tools:context</span>=<span class="value">".MainActivity"</span>
></span>
<span class="tag"><</span><span class="tag"><span class="title">com.jereh.views.MyCircleProgress
</span> <span class="attribute">android:id</span>=<span class="value">"@+id/MyCircleProgress"</span>
<span class="attribute">android:layout_width</span>=<span class="value">"wrap_content"</span>
<span class="attribute">android:layout_height</span>=<span class="value">"wrap_content"</span>
<span class="attribute">app:r</span>=<span class="value">"45"</span>
<span class="attribute">app:strokeWidth</span>=<span class="value">"10"</span>
<span class="attribute">app:bgColor</span>=<span class="value">"#cccccc"</span>
<span class="attribute">app:fgColor</span>=<span class="value">"#ff0000"</span>
<span class="attribute">app:drawStyle</span>=<span class="value">"FILL"</span>
<span class="attribute">app:max</span>=<span class="value">"50"</span>
/></span>
<span class="tag"></</span><span class="tag"><span class="title">RelativeLayout</span>></span>
6、 自定义组件MyCircleProgress中重写onDraw方法:
<span class="keyword">protected</span> <span class="keyword">void</span> onDraw(Canvas canvas) {
<span class="keyword">super</span>.onDraw(canvas);
<span class="keyword">int</span> center = getWidth() / <span class="number">2</span>; <span class="comment">//</span><span class="comment"> 圆心位置</span>
<span class="keyword">this</span>.paint.setColor(bgColor);
<span class="keyword">this</span>.paint.setStrokeWidth(strokeWidth);
canvas.drawCircle(center, center, mR, <span class="keyword">this</span>.paint);
<span class="comment">//</span><span class="comment"> 绘制圆环</span>
<span class="keyword">this</span>.paint.setColor(fgColor);
<span class="keyword">if</span>(drawStyle==<span class="number"></span>){
<span class="keyword">this</span>.paint.setStyle(Style.STROKE);
opt=<span class="keyword">false</span>;
}<span class="keyword">else</span>{
<span class="keyword">this</span>.paint.setStyle(Style.FILL);
opt=<span class="keyword">true</span>;
}
<span class="keyword">int</span> top = (center - mR);
<span class="keyword">int</span> bottom = (center + mR);
RectF oval = <span class="keyword">new</span> RectF(top, top, bottom, bottom);
canvas.drawArc(oval, <span class="number">270</span>, <span class="number">360</span>*progress/max, opt, paint);
}
7、编写MainActivity
<span class="keyword">public</span> <span class="class"><span class="keyword">class</span></span><span class="class"> <span class="title">MainActivity</span> <span class="keyword">extends</span> <span class="title">Activity</span> {</span>
<span class="keyword">private</span> MyCircleProgress progressView;
<span class="annotation">@Override</span>
<span class="keyword">protected</span> <span class="keyword">void</span> onCreate(Bundle savedInstanceState) {
<span class="keyword">super</span>.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
progressView = (MyCircleProgress) findViewById(R.id.MyCircleProgress);
<span class="keyword">new</span> ProgressAnimation().execute();
}
<span class="class"><span class="keyword">class</span></span><span class="class"> <span class="title">ProgressAnimation</span> <span class="keyword">extends</span> <span class="title">AsyncTask</span><<span class="title">Void</span>, <span class="title">Integer</span>, <span class="title">Void</span>> {</span>
<span class="annotation">@Override</span>
<span class="keyword">protected</span> Void doInBackground(Void... params) {
<span class="comment">//</span><span class="comment">进度值不断的变化</span>
<span class="keyword">for</span> (<span class="keyword">int</span> i = <span class="number"></span>; i < progressView.getMax(); i++) {
<span class="keyword">try</span> {
publishProgress(i);
Thread.sleep(<span class="number">100</span>);
} <span class="keyword">catch</span> (InterruptedException e) {
e.printStackTrace();
}
}
<span class="keyword">return</span> <span class="keyword">null</span>;
}
<span class="annotation">@Override</span>
<span class="keyword">protected</span> <span class="keyword">void</span> onProgressUpdate(Integer... values) {
<span class="comment">//</span><span class="comment">更新进度值</span>
progressView.setProgress(values[<span class="number"></span>]);
progressView.invalidate();
<span class="keyword">super</span>.onProgressUpdate(values);
}
}
}
💬 评论