Android自定义控件系列案例

Posted 张科勇

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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>
效果图:

技术分享

到此就完成了比较灵活的圆形进度条的制作。














以上是关于Android自定义控件系列案例的主要内容,如果未能解决你的问题,请参考以下文章

Android自定义控件系列之基础篇

Android自己定义控件系列案例

android开发系列之使用xml自定义控件

Android进阶之绘制-自定义View完全掌握

[转]Android自定义控件三部曲系列完全解析(动画, 绘图, 自定义View)

android--------自定义控件