Android自定义progressBar


先看下运行后的效果:



一、自定义一个控件 首先当然得继承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,</br>
	 *         CBbaseView.RENDER_RATE_SLOWLY,</br> 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  实现render方法即可。渲染由CBbaseView来完成。当然因为

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;
	}
	
	
}

自定义的progressBar支持圆环样式和横向矩形样式。然后在render()里面根据从attrs.xml文件里面的定义的属性实现不同绘图逻辑。这里贴出我自定义的styleable

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!-- 进度百分比文字大小 -->
    <attr name="percent_text_size" format="dimension" />
    <!-- 圆形进度条边框大小 -->
    <attr name="stroke_width" format="dimension" />
    <!-- 矩形进度条 四周圆角大小 -->
    <attr name="rect_round" format="dimension" />
    <!-- 矩形进度条 是空心样式还是实心样式 -->
    <attr name="isHorizonStroke" format="boolean" />
    <!-- 进度百分比文字颜色 -->
    <attr name="percent_text_color" format="color|integer" />
    <!-- 进度条背景颜色 -->
    <attr name="progressBarBgColor" format="color|integer" />
    <!-- 进度颜色 -->
    <attr name="progressColor" format="color|integer" />
    <!-- 进度条样式圆形还是矩形 -->
    <attr name="orientation">
        <enum name="horizontal" value="0"/>
        <enum name="circle" value="1"/>
    </attr>
    
    <declare-styleable name="cbprogressbar">
        <attr name="percent_text_size"/>
        <attr name="isHorizonStroke"/>
        <attr name="percent_text_color"/>
        <attr name="progressBarBgColor"/>
        <attr name="progressColor"/>
        <attr name="orientation"/>
        <attr name="stroke_width"/>
        <attr name="rect_round"/>
    </declare-styleable>
    
</resources>


三、在项目中使用

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:cb="http://schemas.android.com/apk/res/com.chongbao.ui"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <com.chongbao.ui.activity.CBProgressBar
        android:id="@+id/my_progress"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_gravity="center_horizontal"
        cb:orientation="circle"
        cb:percent_text_color="@color/percent_text_color"
        cb:percent_text_size="@dimen/percent_text_size" />

    <Button
        android:id="@+id/btn_download"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="20dp" />

    <com.chongbao.ui.activity.CBProgressBar
        android:id="@+id/my_progress2"
        android:layout_width="match_parent"
        android:layout_height="20dp"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="20dp"
        cb:isHorizonStroke="true"
        cb:orientation="horizontal"
        cb:percent_text_color="@color/percent_text_color_2"
        cb:percent_text_size="@dimen/percent_text_size_large"
        cb:progressBarBgColor="@color/progressbar_bg_color_1"
        cb:progressColor="@color/progress_color_1" />

</LinearLayout>


















  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值