1. 程式人生 > >Android自定義控制元件系列案例【四】

Android自定義控制元件系列案例【四】

案例效果:


模擬器上執行有些鋸齒,真機上和預期一樣好

案例分析:

看效果,第一直覺肯定是Android原生態控制元件中沒有這樣的控制元件實現這種效果,自然想到應該需要自定義控制元件了,沒錯,這就是通過自定義控制元件來繪製的一個圓環進度條。仔細分析發現這個效果的進度條應該由幾個部分組成,首先是無進度時的淺色圓環,然後是一個隨進度變化的深色圓弧,而中間部分是一個深藍色的實心圓,最後就是顯示進度百分比的文字。這幾部分大部分都是圖形,所以使用圖形繪製技術應該可以繪製出分部分效果,然後加上進度控制部分應該心裡就有底了。

技術實現:

按照上面的分析我們一部分一部分的來實現。先大概列一個步驟: (1)自定義View,重寫構造方法,重寫onDraw()方法。
 重寫onDraw()方法的目的是為了找到繪製圖形的時機與場所。
(2)繪製淺色圓環。
需求準備Paint畫筆,並設定畫筆寬度,顏色,樣式等,然後繪製圓環。
(3)繪製深色進度圓弧。
重置Paint畫筆,並設定畫筆顏色,繪製進度圓弧。
(4)新增SeekBar,並通過進度變化控制進度圓弧。
測試進度圓弧是否會隨進度的變化正常工作。
(5)繪製深藍色實心圓。
重置Paint畫筆,並設定畫筆顏色,繪製實心圓。
(6)繪製百分比文字。
計算進度百分比,繪製文字。
7)自定義屬性,使進度條樣式可配置(擴充套件部分)。
  • 自定義View,重寫構造方法,重寫onDraw()方法
package com.kedi.myprogressbar;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.View;

public class MyProgressBar extends View {

	public MyProgressBar(Context context) {
		this(context, null);
	}
	public MyProgressBar(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}
	public MyProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
	     super(context, attrs, defStyleAttr);
		
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);

	}

}

 有了自定義MyProgressBar,此時就可以在XML佈局中先佔位了,下面是XML佈局檔案。
<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" >

    <com.kedi.myprogressbar.MyProgressBar
        android:id="@+id/pg"
        android:layout_width="120dp"
        android:layout_height="120dp"
        android:padding="5dp"
        android:layout_centerInParent="true" >
    </com.kedi.myprogressbar.MyProgressBar>

    <SeekBar
        android:id="@+id/sb"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/pg"
        android:max="100"
        android:layout_margin="20dp" />

</RelativeLayout>
  • 繪製淺色圓環
Paint 畫筆:
|- new Paint() 建立畫筆
|- setColor() 設定畫筆顏色
|- setStyle()設定畫筆樣式(Paint.Style.STROKE 虛框樣式,Paint.Style.FILL 實心樣式)
|- setStrokeWidth()設定畫筆線寬
|- setAntiAlias()消除鋸齒或毛邊
|- setTextSize()設定畫文字時的文字大小 
|- setTypeface()設定畫文字時的文字字型
Canvas畫布:
|- drawCircle(cx, cy, radius, paint)繪製圓環或圓。cx,cy:圓心座標,radius:圓半徑,paint:畫筆。
|- drawText(text, x, y, paint)繪製文字。text:文字,x,y:文字座標,paint:畫筆。
|- drawArc(oval, startAngle, sweepAngle, useCenter, paint)繪製圓弧。
   oval:矩形區域,用來確定圓弧形狀和大小。new RectF(left, top, right, bottom)確定一個矩形區域。
   startAngle:圓弧始端角度。
   sweepAngle:圓弧末端角度。
   paint:畫筆。
   userCenter:設定是否顯示圓弧的兩邊線條,false時只畫圓弧沒有兩邊,true時帶兩邊。如下圖:

有了這些技術準備,繪製工作將一路順利。為了進行接下來的繪製工作,先在初始化方法中建立一個空畫筆。
public class MyProgressBar extends View {
	private Paint paint;// 畫筆
	public MyProgressBar(Context context) {
		this(context, null);
	}
	public MyProgressBar(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}
	public MyProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
	     super(context, attrs, defStyleAttr);
	     init();		
	}
	/**
	 * 初始化方法
	 */
	private void init() {
	    paint = new Paint();		
	}
	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);

	}

}
接下來繪製淺色圓環 核心邏輯:
private int roundW;// 圓環寬
/**
 * 初始化方法
 */
private void init() {
   paint = new Paint();
 //初始化圓環寬,這裡考慮了適配把15dp進行了對應平臺的畫素轉換。
 roundW = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 15, getResources().getDisplayMetrics());

}
	       // 1.圓心(x,y)座標值
		int centerX = getWidth() / 2;
		int centerY = centerX;
		// 2.圓環半徑
		int radius1 = (centerX - roundW / 2);
		// 3.設定圓環顏色(淺色)
		paint.setColor(Color.parseColor("#11339ED4"));
		// 4.設定畫筆的風格
		paint.setStyle(Paint.Style.STROKE);
		// 5.設定畫圓環的寬度
		paint.setStrokeWidth(roundW);
		// 6.消除鋸齒
		paint.setAntiAlias(true);
		// 7.畫圓環
		canvas.drawCircle(centerX, centerY, radius1, paint);
完整程式碼(如何是直接拷貝這塊程式碼的時候記的修改包名和導包):
package com.kedi.myprogressbar;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;

public class MyProgressBar extends View {
	private Paint paint;// 畫筆
	private int roundW;// 圓環寬

	public MyProgressBar(Context context) {
		this(context, null);
	}

	public MyProgressBar(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public MyProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		init();
	}

	/**
	 * 初始化方法
	 */
	private void init() {
		paint = new Paint();
		// 初始化圓環寬,這裡考慮了適配把15dp進行了對應平臺的畫素轉換。
		roundW = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 15, getResources().getDisplayMetrics());
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		// 繪製淺色圓環
		// 1.圓心(x,y)座標值
		int centerX = getWidth() / 2;
		int centerY = centerX;
		// 2.圓環半徑
		int radius1 = (centerX - roundW / 2);
		// 3.設定畫大圓環顏色
		paint.setColor(Color.parseColor("#11339ED4"));
		// 4.設定畫筆的風格
		paint.setStyle(Paint.Style.STROKE);
		// 5.設定畫圓環的寬度
		paint.setStrokeWidth(roundW);
		// 6.消除鋸齒
		paint.setAntiAlias(true);
		// 7.畫圓環
		canvas.drawCircle(centerX, centerY, radius1, paint);
	}
}
效果圖:
  • 繪製深色進度圓弧

        圓弧的繪製重點在開始角度和末端角度的計算和確定,因為我們的圓弧代表進度,所以開始角度和末端角度都與進度有關,會跟著進度的變化而變化,所以首先我們的確定當前進度和最大進度。然後就可以計算始末角度了。

定義進度值:
private int progress = 0;// 當前進度值
private int maxProgress = 100;// 最大進度值
進度改變介面方法:
/**
	 * 更新進度和介面的方法
	 * 
	 * @param progress
	 */
	public void setProgress(int progress) {
		if (progress < 0) {
			progress = 0;
		} else {
			this.progress = progress;
		}
		invalidate();
	}
計算始末角度:
開始角度 0
末端角度 (float)360 * progress / (float)maxProgress
核心邏輯:
		//繪製深色進度圓弧
		// 1.設定圓孤的寬度
		paint.setStrokeWidth(roundW);
		// 2.設定圓孤進度的顏色
		paint.setColor(Color.parseColor("#339ED4"));
		// 3.定義圓弧的形狀和大小區域
		RectF oval = new RectF(centerX - radius1, centerY - radius1, centerX + radius1, centerY + radius1);
		// 4.設定空心樣式
		paint.setStyle(Paint.Style.STROKE);
		// 5.根據進度畫圓弧
		canvas.drawArc(oval, 0, (float)360 * progress / (float)maxProgress, false, paint);
完整程式碼(為了測試進度效果,我們先把progress=20,測試完再設定為progress=0):
package com.kedi.myprogressbar;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;

public class MyProgressBar extends View {
	private Paint paint;// 畫筆
	private int roundW;// 圓環寬
	private int progress = 20;// 當前進度值
	private int maxProgress = 100;// 最大進度值

	/**
	 * 更新進度和介面的方法
	 * 
	 * @param progress
	 */
	public void setProgress(int progress) {
		if (progress < 0) {
			progress = 0;
		} else {
			this.progress = progress;
		}
		invalidate();
	}

	public MyProgressBar(Context context) {
		this(context, null);
	}


	public MyProgressBar(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	public MyProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		init();
	}

	/**
	 * 初始化方法
	 */
	private void init() {
		paint = new Paint();
		roundW = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 15, getResources().getDisplayMetrics());

	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		// 繪製淺色圓環
		// 1.圓心(x,y)座標值
		int centerX = getWidth() / 2;
		int centerY = centerX;
		// 2.圓環半徑
		int radius1 = (centerX - roundW / 2);
		// 3.設定畫大圓環顏色
		paint.setColor(Color.parseColor("#11339ED4"));
		// 4.設定畫筆的風格
		paint.setStyle(Paint.Style.STROKE);
		// 5.設定畫圓環的寬度
		paint.setStrokeWidth(roundW);
		// 6.消除鋸齒
		paint.setAntiAlias(true);
		// 7.畫圓環
		canvas.drawCircle(centerX, centerY, radius1, paint);
		
		// 繪製深色進度圓弧
		// 1.設定圓孤的寬度
		paint.setStrokeWidth(roundW);
		// 2.設定圓孤進度的顏色
		paint.setColor(Color.parseColor("#339ED4"));
		// 3.定義圓弧的形狀和大小區域界限
		RectF oval = new RectF(centerX - radius1, centerY - radius1, centerX + radius1, centerY + radius1);
		// 4.設定空心樣式
		paint.setStyle(Paint.Style.STROKE);
		// 5.根據進度畫圓弧
		canvas.drawArc(oval, 0, (float) 360 * progress / (float) maxProgress, false, paint);
	}
}
效果圖:
  • 新增SeekBar,並通過進度變化控制進度圓弧

這塊主要是通過SeekBar進度的改變來更新進度圓弧的動態改變,邏輯很簡單,監聽SeekBar進度改變,然後把改變的進度通過setProgress()方法傳給自定義控制元件,觸發自定義控制元件重新呼叫onDraw()方法,根據新進度值重繪圓弧。

完整程式碼:

<span style="font-weight: normal;"><span style="font-size:14px;">package com.kedi.myprogressbar;

import android.app.Activity;
import android.os.Bundle;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;

public class MainActivity extends Activity {
	//自定義進度條控制元件
	private MyProgressBar pg;
	//SeekBar控制元件
	private SeekBar sb;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		initViews();
		initEvents();
	}
	/**
	 * 初始化View
	 */
	private void initViews(){
		pg =(MyProgressBar) findViewById(R.id.pg);
		sb = (SeekBar) findViewById(R.id.sb);
		
	}
	/**
	 * 初始化事件監聽與處理
	 */
	private void initEvents() {
		sb.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
			
			@Override
			public void onStopTrackingTouch(SeekBar seekBar) {
				
			}
			
			@Override
			public void onStartTrackingTouch(SeekBar seekBar) {
				
			}
			
			@Override
			public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
				//改變圓弧的進度,並重新繪製圓弧,主要是通過觸發自定義控制元件的onDraw()方法達到目的
				pg.setProgress(progress);
			}
		});
	}
}</span></span>
效果圖:                                                                  
  • 繪製深藍色實心圓

實心圓的繪製也是通過drawCircle()方法,只是畫筆的樣式為FILL實心,所以比較簡單。

核心程式碼:

	// 繪製深藍色實心圓
		 // 1.實心圓半徑
		 int radius2 = centerX - roundW;
		 // 2.實心圓顏色
		 paint.setColor(Color.parseColor("#336799"));
		 // 3.設定畫筆風格為實心
		 paint.setStyle(Paint.Style.FILL);
		 // 4.畫實心圓
		 canvas.drawCircle(centerX, centerY, radius2, paint);
效果圖:
  • 繪製百分比文字

繪製文字需要知道文字大小,文字字型,文字顏色,文字x,y座標位置以及文字內容。

文字大小我們定義個成員變數,然後在init()方法中初始化,當然可以對外提供介面方法,設定文字大小,

文字顏色使用白色,當然也可以像文字大小那樣定義成員變數,然後初始化,也可對外提供介面方法,設定文字顏色

文字x,y座標需要根據圓心座標與文字自身的寬高進行計算。

文字內容是進度百分比,需要根據進度進行計算。(float) progress / (float) maxProgress) * 100

核心邏輯:

     // 繪製百分比文字
		// 1.設定無邊框
		paint.setStrokeWidth(0);
		// 2.設定字型顏色
		paint.setColor(Color.WHITE);
		paint.setAntiAlias(true);
		// 3.設定字型大小,定義成員變數textSize,然後在初始化方法中賦初始值
		paint.setTextSize(textSize);
		// 4.設定字型
		paint.setTypeface(Typeface.DEFAULT_BOLD);
		// 5.計算進度百分比
		int percent = (int) (((float) progress / (float) maxProgress) * 100);
		// 6.測量字型寬度
		float textWidth = paint.measureText(percent + "%");
		// 7.畫出進度百分比文字
		canvas.drawText(percent + "%", centerX - textWidth / 2, centerY + textSize / 2, paint);

完整程式碼:

package com.kedi.myprogressbar;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;

public class MyProgressBar extends View {
	private Paint paint;// 畫筆
	private int roundW;// 圓環寬
	private int textSize;// 字型大小
	private int progress = 0;// 當前進度值
	private int maxProgress = 100;// 最大進度值

	/**
	 * 更新進度和介面的方法
	 * 
	 * @param progress
	 */
	public void setProgress(int progress) {
		if (progress < 0) {
			progress = 0;
		} else {
			this.progress = progress;
		}
		invalidate();
	}

	/**
	 * @param context
	 */
	public MyProgressBar(Context context) {
		this(context, null);
	}

	/**
	 * @param context
	 * @param attrs
	 */
	public MyProgressBar(Context context, AttributeSet attrs) {
		this(context, attrs, 0);
	}

	/**
	 * @param context
	 * @param attrs
	 * @param defStyleAttr
	 */
	public MyProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		init();
	}

	/**
	 * 初始化方法
	 */
	private void init() {
		paint = new Paint();
		roundW = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 15, getResources().getDisplayMetrics());
		textSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 25, getResources().getDisplayMetrics());
	}

	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		// 繪製淺色圓環
		// 1.圓心(x,y)座標值
		int centerX = getWidth() / 2;
		int centerY = centerX;
		// 2.圓環半徑
		int radius1 = (centerX - roundW / 2);
		// 3.設定畫大圓環顏色
		paint.setColor(Color.parseColor("#11339ED4"));
		// 4.設定畫筆的風格
		paint.setStyle(Paint.Style.STROKE);
		// 5.設定畫圓環的寬度
		paint.setStrokeWidth(roundW);
		// 6.消除鋸齒
		paint.setAntiAlias(true);
		// 7.畫圓環
		canvas.drawCircle(centerX, centerY, radius1, paint);
		
		// 繪製深色進度圓弧
		// 1.設定圓孤的寬度
		paint.setStrokeWidth(roundW);
		// 2.設定圓孤進度的顏色
		paint.setColor(Color.parseColor("#339ED4"));
		// 3.定義圓弧的形狀和大小區域界限
		RectF oval = new RectF(centerX - radius1, centerY - radius1, centerX + radius1, centerY + radius1);
		// 4.設定空心樣式
		paint.setStyle(Paint.Style.STROKE);
		// 5.根據進度畫圓弧
		canvas.drawArc(oval, 0, (float) 360 * progress / (float) maxProgress, false, paint);
		
		// 繪製深藍色實心圓
		// 1.實心圓半徑
		int radius2 = centerX - roundW;
		// 2.實心圓顏色
		paint.setColor(Color.parseColor("#336799"));
		// 3.設定畫筆風格為實心
		paint.setStyle(Paint.Style.FILL);
		// 4.畫實心圓
		canvas.drawCircle(centerX, centerY, radius2, paint);
		
		// 繪製百分比文字
		// 1.設定無邊框
		paint.setStrokeWidth(0);
		// 2.設定字型顏色
		paint.setColor(Color.WHITE);
		// 3.設定字型大小
		paint.setTextSize(textSize);
		// 4.設定字型
		paint.setTypeface(Typeface.DEFAULT_BOLD);
		// 5.計算進度百分比
		int percent = (int) (((float) progress / (float) maxProgress) * 100);
		// 6.測量字型寬度
		float textWidth = paint.measureText(percent + "%");
		// 7.畫出進度百分比文字
		canvas.drawText(percent + "%", centerX - textWidth / 2, centerY + textSize / 2, paint);
	}
}
效果圖:
到此實現的效果已經與我們一開始看到的效果分毫不差了。
  • 自定義屬性,使進度條樣式可配置(擴充套件部分)

效果已經實現完了,但是如果我的專案中需要一個其它主題風格的進度條,那我們不得不重新Copy一份,然後修改其中的顏色值什麼的,這樣的自定義控制元件顯然不夠靈活和通用,如果進度條提供了對主題風格的定製介面那就靈活不少,所以接下來做為擴充套件部分,要做的是為進度條提供主題風格定製途徑---自定義屬性與Setter方法。

經分析,把與樣式相關的特徵都定義成成員變數,有如下幾個:

	//圓環相關成員變數
	 private int roundW;// 圓環寬
	 private int roundColor;//圓環顏色

	//圓弧相關成員變數
	 private int progress;// 當前進度值
	 private int progressColor;//進度圓弧顏色
	 private int maxProgress = 100;// 最大進度值

	//實心圓相關成員變數
   	 private int circleColor;//實心圓顏色

   	 //百分比文字相關成員變數
   	 private int textColor;//字型顏色
   	 private int textSize;// 字型大小

定義自定義屬性檔案values/attrs.xml,並定義成上面成員變數一一對應的自定義屬性:

<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
    <declare-styleable name="MyProgressBarSytle">
        <!-- 圓環相關 -->
        <attr name="roundW" format="dimension" />
        <attr name="roundColor" format="color" />
        <!-- 圓弧相關 -->
        <attr name="progress" format="integer" />
        <attr name="progressColor" format="color" />
        <attr name="maxProgress" format="integer" />
        <!-- 實心圓相關 -->
        <attr name="circleColor" format="color" />

        <!-- 百分比文字相關 -->
        <attr name="textColor" format="color" />
        <attr name="textSize" format="dimension" />
    </declare-styleable>
</resources>
構造方法中獲取自定義屬性,然後初始化上面的那幾個成員變數(將原來的值做為預設值):
public MyProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
		super(context, attrs, defStyleAttr);
		init(attrs);
	}

	private void init(AttributeSet attrs) {
		paint = new Paint();
	    TypedArray typedArray = getContext().obtainStyledAttributes(attrs, R.styleable.MyProgressBarSytle);
		
	    roundW = (int) typedArray.getDimension(R.styleable.MyProgressBarSytle_roundW, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 15, getResources().getDisplayMetrics()));
	    roundColor = typedArray.getColor(R.styleable.MyProgressBarSytle_roundColor, Color.parseColor("#11339ED4"));
	    progress = typedArray.getInt(R.styleable.MyProgressBarSytle_progress, 0);
	    progressColor = typedArray.getColor(R.styleable.MyProgressBarSytle_progressColor, Color.parseColor("#339ED4"));
	    
	    circleColor = typedArray.getColor(R.styleable.MyProgressBarSytle_circleColor, Color.parseColor("#336799"));
	    
	    textColor = typedArray.getColor(R.styleable.MyProgressBarSytle_textColor, Color.parseColor("#ffffff"));	    
	    textSize = (int) typedArray.getDimension(R.styleable.MyProgressBarSytle_textSize, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 25, getResources().getDisplayMetrics()));
	    
	    typedArray.recycle();
	}

將繪製邏輯各分部中樣式原來的值,換成成員變數:

@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		//繪製淺色圓環
		// 1.圓心(x,y)座標值
		int centerX = getWidth() / 2;
		int centerY = centerX;
		// 2.圓環半徑
		int radius1 = (centerX - roundW / 2);
		// 3.設定畫大圓環顏色
		paint.setColor(roundColor);
		// 4.設定畫筆的風格
		paint.setStyle(Paint.Style.STROKE);
		// 5.設定畫圓環的寬度
		paint.setStrokeWidth(roundW);
		// 6.消除鋸齒
		paint.setAntiAlias(true);
		// 7.畫圓環
		canvas.drawCircle(centerX, centerY, radius1, paint);

		// 繪製深色進度圓弧
		// 1.設定圓孤的寬度
		paint.setStrokeWidth(roundW);
		// 2.設定圓孤進度的顏色
		paint.setColor(progressColor);
		// 3.定義圓弧的形狀和大小區域界限
		RectF oval = new RectF(centerX - radius1, centerY - radius1, centerX + radius1, centerY + radius1);
		// 4.設定空心樣式
		paint.setStyle(Paint.Style.STROKE);
		// 5.根據進度畫圓弧
		canvas.drawArc(oval, 0, (float) 360 * progress / (float) maxProgress, false, paint);

		// 繪製深藍色實心圓
		// 1.實心圓半徑
		int radius2 = centerX - roundW;
		// 2.實心圓顏色
		paint.setColor(circleColor);
		// 3.設定畫筆風格為實心
		paint.setStyle(Paint.Style.FILL);
		// 4.畫實心圓
		canvas.drawCircle(centerX, centerY, radius2, paint);

		// 繪製百分比文字
		// 1.設定無邊框
		paint.setStrokeWidth(0);
		// 2.設定字型顏色
		paint.setColor(textColor);
		paint.setAntiAlias(true);
		// 3.設定字型大小
		paint.setTextSize(textSize);
		// 4.設定字型
		paint.setTypeface(Typeface.DEFAULT_BOLD);
		// 5.計算進度百分比
		int percent = (int) (((float) progress / (float) maxProgress) * 100);
		// 6.測量字型寬度
		float textWidth = paint.measureText(percent + "%");
		// 7.畫出進度百分比文字
		canvas.drawText(percent + "%", centerX - textWidth / 2, centerY + textSize / 2, paint);

	}
 如果我們希望通過程式碼也可以修改這些樣式值,就對外提供Setter方法:
 /**
     * 設定圓環寬度
     * @param roundW
     */
	public void setRoundW(int roundW) {
		this.roundW = roundW;
	}
	/**
	 * 設定圓環顏色
	 * @param roundColor
	 */
	public void setRoundColor(int roundColor) {
		this.roundColor = roundColor;
	}
	/**
	 * 設定進度圓弧顏色
	 * @param progressColor
	 */
	public void setProgressColor(int progressColor) {
		this.progressColor = progressColor;
	}
	/**
	 * 設定最大進度值
	 * @param maxProgress
	 */
	public void setMaxProgress(int maxProgress) {
		this.maxProgress = maxProgress;
	}
	/**
	 * 設定實心圓顏色
	 * @param circleColor
	 */
	public void setCircleColor(int circleColor) {
		this.circleColor = circleColor;
	}
	/**
	 * 設定百分比進度文字顏色
	 * @param textColor
	 */
	public void setTextColor(int textColor) {
		this.textColor = textColor;
	}
	/**
	 * 設定百分比進度文字字型大小
	 * @param textSize
	 */
	public void setTextSize(int textSize) {
		this.textSize = textSize;
	}

	/**
	 * 更新進度和介面的方法
	 * 
	 * @param progress
	 */
	public void setProgress(int progress) {
		if (progress < 0) {
			progress = 0;
		} else {
			this.progress = progress;
		}
		invalidate();
	}
最後演示一下使用自定義屬性定製主題的方式:

(1)在根佈局中新增名稱空間

         xmlns:my="http://schemas.android.com/apk/res-auto"

        其中my是是名稱空間名,可隨意指定,而“http://schemas.android.com/apk/res-auto”是固定的名稱空間。

(2)使用自定義屬性並指定屬性值


完整佈局程式碼:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:my="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <com.kedi.myprogressbar.MyProgressBar
        android:id="@+id/pg"
        android:layout_width="120dp"
        android:layout_height="120dp"
        android:layout_centerInParent="true"
        android:padding="5dp"
        my:circleColor="#ACD900"
        my:maxProgress="100"
        my:progressColor="#FF6400"
        my:roundColor="#316900"
        my:roundW="8dp"
        my:textColor="#EE3400"
        my:textSize="20sp" >
    </com.kedi.myprogressbar.MyProgressBar>

    <SeekBar
        android:id="@+id/sb"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/pg"
        android:layout_margin="20dp"
        android:max="100" />

</RelativeLayout>
效果圖:



到此就完成了比較靈活的圓形進度條的製作。