先看下运行后的效果:
一、自定义一个控件 首先当然得继承View 。不过后来又换成是继承了一个surfaceView。因为绘图渲染效率更高。
先看下这个 继承了SurfaceView的View:
/**
* 一个继承SurfaceView的绘图基类。提高绘图效率。如果不是做游戏等需要高效率绘图刷新的应用时,可以在view加载完成的时候调用stopRender(
* )停止绘图渲染
*
* @author zhl
*
*/
public abstract class CBbaseView extends SurfaceView implements Callback,
Runnable {
/**绘图渲染频率 正常**/
public static final int RENDER_RATE_NORMAL = 0;
/** 绘图渲染频率 较慢 **/
public static final int RENDER_RATE_SLOWLY = 1;
/** 绘图渲染频率 较慢 **/
public static final int RENDER_RATE_FAST = 2;
private long sleepMillions = 50;
/** 控制、访问Surface **/
SurfaceHolder holder;
/** 用来绘图的子线程 **/
Thread thread;
/** 是否要绘图 **/
boolean isRender;
/** 画笔 **/
Paint paint;
public CBbaseView(Context context) {
this(context, null);
}
public CBbaseView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CBbaseView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
// 这两句设置防止 sufraceview出现黑色背景
setZOrderOnTop(true);
// 1.获取Holder
holder = getHolder();
holder.setFormat(PixelFormat.TRANSLUCENT);
// 初始化画笔
paint = new Paint(Paint.ANTI_ALIAS_FLAG);
// 2.监听Surface的生命周期
holder.addCallback(this);
}
/**
* Callback-Surface被创建
*/
public void surfaceCreated(SurfaceHolder holder) {
// 3.开启子线程
thread = new Thread(this);
isRender = true;
thread.start();
System.out.println("surfaceCreated");
}
/**
* Callback-Surface的尺寸被改变
*/
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
System.out.println("surfaceChanged");
}
/**
* Callback-Surface被销毁
*/
public void surfaceDestroyed(SurfaceHolder holder) {
System.out.println("surfaceDestroyed");
isRender = false;
if (thread != null && thread.isAlive()) {
try {
thread.join();
} catch (Exception e) {
e.printStackTrace();
}
}
}
/**
* 绘图
*/
public void run() {
Canvas canvas = null;
while (isRender) {
try {
// 4.拿到Canvas进行绘图,并且缓存到Surface
canvas = holder.lockCanvas();
// 清理屏幕
canvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
render(canvas, paint);
} finally {
// 5.解锁画布,回到主线程进行渲染
if (canvas != null) {
holder.unlockCanvasAndPost(canvas);
}
}
// 休息50ms
try {
Thread.sleep(sleepMillions);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
/**
* 真正的绘图逻辑
*/
protected abstract void render(Canvas canvas, Paint piant);
/**
* 停止绘图(由于本类一直循环绘图,在view不需要一直加载的情况下 可以调用此方法停止绘图,停止绘图后 重新绘图需要调用reStart())
*/
protected void stopRender() {
// 停止渲染时 先睡一下 防止 之前的视图没有及时更新而停止渲染
try {
Thread.sleep(sleepMillions);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.isRender = false;
}
/**
* 重新开始绘图(重新开启一个绘图线程)
*/
protected void reStartRender() {
thread = new Thread(this);
isRender = true;
thread.start();
}
/**
* 是否正在进行绘图渲染
*
* @return true/false true:可以绘图 false: 需要调用restart()才能绘图
*/
protected boolean isRending() {
return this.isRender;
}
/**
* 设置刷新频率
*
* @params CBbaseView.RENDER_RATE_NORMAL,
* CBbaseView.RENDER_RATE_SLOWLY, CBbaseView.RENDER_RATE_FAST
*/
protected void setRenderRate(int rate) {
if (rate < 0) {
return;
}
switch (rate) {
case RENDER_RATE_NORMAL:
sleepMillions = 50;
break;
case RENDER_RATE_SLOWLY:
sleepMillions = 100;
break;
case RENDER_RATE_FAST:
sleepMillions = 30;
break;
default:
break;
}
}
}
CBbaseView开启了循环。相对较耗性能。所以可以调用setRenderRate设置刷新频率。而且在View加载完成不需要再绘图的时候。可以调用stopRender()方法停止绘图渲染。需要再次绘图渲染的时候先调用reStartRender()方法即可。
二、现在开始写自定义的ProgressBar继承CBbaseView 在内部实现render方法进行绘图
/**
* 自定义的progressBar继承一个surfaceView提高绘图效率,当然也会比view耗性能
* @author zhl
*
*/
public class CBProgressBar extends CBbaseView {
private static final int STYLE_HORIZONTAL=0;
private static final int STYLE_ROUND=1;
/**进度背景画笔**/
// private Paint mBgpaint;
/**进度画笔**/
// private Paint mPrgpaint;
/**进度文字画笔**/
// private Paint mTextpaint;
/**圆形进度条边框宽度**/
private int strokeWidth;
/**进度条中心X坐标**/
private int centerX;
/**进度条中心Y坐标**/
private int centerY;
/**进度提示文字大小**/
private int percenttextsize=0;
/**进度提示文字颜色**/
private int percenttextcolor=0;
/**进度条背景颜色**/
private int progressBarBgColor=0;
/**进度颜色**/
private int progressColor=0;
/**进度条样式(水平/圆形)**/
private int orientation=0;
/**圆形进度条半径**/
private int radius = 0;
/**进度最大值**/
private int max = 0;
/**进度值**/
private int progress = 0;
/**水平进度条是否是空心**/
private boolean isHorizonStroke;
/**水平进度圆角值**/
private int rectRound;
public CBProgressBar(Context context){
this(context, null);
}
public CBProgressBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CBProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.cbprogressbar);
percenttextcolor = array.getColor(R.styleable.cbprogressbar_percent_text_color, getResources().getColor(R.color.percent_text_color_default));
progressBarBgColor = array.getColor(R.styleable.cbprogressbar_progressBarBgColor, getResources().getColor(R.color.progressbar_bg_color_default));
progressColor = array.getColor(R.styleable.cbprogressbar_progressColor, getResources().getColor(R.color.progress_color_default));
percenttextsize = (int) array.getDimension(R.styleable.cbprogressbar_percent_text_size, getResources().getDimension(R.dimen.percent_text_size_default));
strokeWidth = (int) array.getDimension(R.styleable.cbprogressbar_stroke_width, getResources().getDimension(R.dimen.round_width_default));
rectRound = (int) array.getDimension(R.styleable.cbprogressbar_rect_round, getResources().getDimension(R.dimen.round_width_default));
orientation = array.getInteger(R.styleable.cbprogressbar_orientation, 0);
isHorizonStroke = array.getBoolean(R.styleable.cbprogressbar_isHorizonStroke, false);
// mBgpaint = new Paint(Paint.ANTI_ALIAS_FLAG);
// mPrgpaint = new Paint(Paint.ANTI_ALIAS_FLAG);
// mTextpaint = new Paint(Paint.ANTI_ALIAS_FLAG);
array.recycle();
}
@Override
protected void render(Canvas canvas, Paint piant) {
centerX = getWidth()/2;
centerY = getHeight()/2;
radius = centerX-strokeWidth/2;
if(orientation==STYLE_HORIZONTAL){
drawHoriRectProgressBar(canvas,piant);
}else{
drawRoundProgressBar(canvas,piant);
}
}
/**
* 绘制圆形进度条
* @param canvas
*/
private void drawRoundProgressBar(Canvas canvas,Paint piant){
// 初始化画笔属性
piant.setColor(progressBarBgColor);
piant.setStyle(Paint.Style.STROKE);
piant.setStrokeWidth(strokeWidth);
// 画圆
canvas.drawCircle(centerX, centerY, radius, piant);
// 画圆形进度
piant.setColor(progressColor);
piant.setStyle(Paint.Style.STROKE);
piant.setStrokeWidth(strokeWidth);
RectF oval = new RectF(centerX - radius, centerY - radius, radius+ centerX, radius + centerY);
canvas.drawArc(oval, -90, 360*progress/max, false, piant);
// 画进度文字
piant.setStyle(Paint.Style.FILL);
piant.setColor(percenttextcolor);
piant.setTextSize(percenttextsize);
String percent = (int)(progress*100/max)+"%";
Rect rect = new Rect();
piant.getTextBounds(percent, 0, percent.length(), rect);
float textWidth = rect.width();
float textHeight = rect.height();
if(textWidth>=radius*2){
textWidth = radius*2;
}
canvas.drawText(percent, centerX-textWidth/2, centerY+textHeight/2, piant);
}
/**
* 绘制水平矩形进度条
* @param canvas
*/
private void drawHoriRectProgressBar(Canvas canvas,Paint piant){
// 初始化画笔属性
piant.setColor(progressBarBgColor);
if(isHorizonStroke){
piant.setStyle(Paint.Style.STROKE);
piant.setStrokeWidth(1);
}else{
piant.setStyle(Paint.Style.FILL);
}
// 画水平矩形
canvas.drawRoundRect(new RectF(centerX - getWidth()/2, centerY - getHeight()/2,
centerX+getWidth()/2, centerY + getHeight()/2), rectRound, rectRound, piant);
// 画水平进度
piant.setStyle(Paint.Style.FILL);
piant.setColor(progressColor);
canvas.drawRoundRect(new RectF(centerX - getWidth()/2, centerY - getHeight()/2,
((progress*100/max)*getWidth())/100, centerY + getHeight()/2), rectRound, rectRound, piant);
// 画进度文字
piant.setStyle(Paint.Style.FILL);
piant.setColor(percenttextcolor);
piant.setTextSize(percenttextsize);
String percent = (int)(progress*100/max)+"%";
Rect rect = new Rect();
piant.getTextBounds(percent, 0, percent.length(), rect);
float textWidth = rect.width();
float textHeight = rect.height();
if(textWidth>=getWidth()){
textWidth = getWidth();
}
canvas.drawText(percent, centerX-textWidth/2, centerY+textHeight/2, piant);
}
public void updateProgress(int progress){
if(progress>max){
progress = max;
}else{
this.progress = progress;
// postInvalidate();
}
}
public void setMax(int max){
this.max=max;
}
public int getStrokeWidth() {
return strokeWidth;
}
public void setStrokeWidth(int strokeWidth) {
this.strokeWidth = strokeWidth;
}
public int getPercenttextsize() {
return percenttextsize;
}
public void setPercenttextsize(int percenttextsize) {
this.percenttextsize = percenttextsize;
}
public int getPercenttextcolor() {
return percenttextcolor;
}
public void setPercenttextcolor(int percenttextcolor) {
this.percenttextcolor = percenttextcolor;
}
public int getProgressBarBgColor() {
return progressBarBgColor;
}
public void setProgressBarBgColor(int progressBarBgColor) {
this.progressBarBgColor = progressBarBgColor;
}
public int getProgressColor() {
return progressColor;
}
public void setProgressColor(int progressColor) {
this.progressColor = progressColor;
}
public int getOrientation() {
return orientation;
}
public void setOrientation(int orientation) {
this.orientation = orientation;
}
public boolean isHorizonStroke() {
return isHorizonStroke;
}
public void setHorizonStroke(boolean isHorizonStroke) {
this.isHorizonStroke = isHorizonStroke;
}
public int getRectRound() {
return rectRound;
}
public void setRectRound(int rectRound) {
this.rectRound = rectRound;
}
public int getMax() {
return max;
}
public int getProgress() {
return progress;
}
}