**一、概述**

在上一篇博文中,我们给大家介绍了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&lt;<span class="number"></span>){
      progress=<span class="number"></span>;
    }<span class="keyword">else</span> <span class="keyword">if</span>(progress&gt;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">&lt;?</span><span class="pi">xml version="1.0" encoding="utf-8"?&gt;</span>
<span class="tag">&lt;</span><span class="tag"><span class="title">resources</span>&gt;</span>
  <span class="tag">&lt;</span><span class="tag"><span class="title">declare-styleable</span> <span class="attribute">name</span>=<span class="value">"CircleProgressBar"</span>&gt;</span>
    <span class="tag">&lt;</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>/&gt;</span>
    <span class="tag">&lt;</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>/&gt;</span>
    <span class="tag">&lt;</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>/&gt;</span>
    <span class="tag">&lt;</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>/&gt;</span>
    <span class="tag">&lt;</span><span class="tag"><span class="title">attr</span> <span class="attribute">name</span>=<span class="value">"drawStyle"</span>&gt;</span>
      <span class="tag">&lt;</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>&gt;</span><span class="tag">&lt;/</span><span class="tag"><span class="title">enum</span>&gt;</span>
      <span class="tag">&lt;</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>&gt;</span><span class="tag">&lt;/</span><span class="tag"><span class="title">enum</span>&gt;</span>
    <span class="tag">&lt;/</span><span class="tag"><span class="title">attr</span>&gt;</span>
    <span class="tag">&lt;</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>/&gt;</span>
  <span class="tag">&lt;/</span><span class="tag"><span class="title">declare-styleable</span>&gt;</span>
<span class="tag">&lt;/</span><span class="tag"><span class="title">resources</span>&gt;</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">&lt;</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>
     &gt;</span>   
 <span class="tag">&lt;</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>
   /&gt;</span>
<span class="tag">&lt;/</span><span class="tag"><span class="title">RelativeLayout</span>&gt;</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>&lt;<span class="title">Void</span>, <span class="title">Integer</span>, <span class="title">Void</span>&gt; {</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 &lt; 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);
    }
  }
}