android下打造个性化的圆形进度条

本文介绍了一种自定义安卓圆形进度条的方法,通过继承View并利用Canvas进行绘制,实现了多种样式和参数的自由配置,包括颜色、宽度、文本显示等。

在android开发中,算的上常用的View,那ProgressBar是比较常用的View之一了,但是这里有个非常让人头疼的问题,就是系统自带的比较丑陋,但是UI设计出来的效果图和系统的样式差别非常大,这时系统的ProgressBar没法满足用户的需求,于是就有了今天的博文,该博文就是叫你如何打造千变万化的ProgressBar,各种样式,各种参数随心设置,我相信该View一定能满足你在项目中想实现的绝大部分需求。好,那废话就先说到这里,我们开始进入我们今天这边博文的讲解,按照写博文的惯例,先上效果图,是不是有种心动的感觉了,是不是感觉很不错,是不是感觉系统的很丑陋。

1.实现原理:

利用自定View的绘制技术实现.

2.知识储备

   a.自定View的绘制流程

   b.基本的数学计算

   c.字体的宽高计算

   d.Canvas类的使用

   4.自定义属性

package com.example.circleprogressview;


import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Cap;
import android.graphics.Paint.FontMetrics;
import android.graphics.Paint.Style;
import android.graphics.RectF;
import android.os.Looper;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;


public class CircleProgress extends View {


private static final int DEFAULT_FIRST_CIRCLE_COLOR = Color.BLACK;


private static final int DEFAULT_FIRST_CIRCLE_WIDTH = 4;


private static final int DEFAULT_SECOND_CIRLCE_COLOR = Color.WHITE;


private static final int DEFAULT_MAX_PROGRESS = 100;


private static final int DEFAULT_START_PROGRESS = 0;
private static final int DEFAULT_PROGRESS_TEXT_COLOR = DEFAULT_SECOND_CIRLCE_COLOR;


private static final int DEFAULT_PROGRESS_TEXT_SIZE = 16;


private static final boolean DEFAULT_IS_SHOW_PROGRESS_TEXT = true;


private static final Cap DEFAULT_CIRCLE_CAP = Cap.SQUARE;


private static final int BUTT_CAP = 0;


private static final int SQUARE_CAP = 1;


private static final int ROUND_CAP = 2;


private int mFirstCircleColor;


private int mFirstCircleWidth;


private int mSecondCircleColor;


private int maxProgress;


private int mStartProgess;


private int mProgressTextColor;


private int mProgressTextSize;


private Paint mPaint;


private boolean isShowProgressText;


private int mCurrentProgress = DEFAULT_START_PROGRESS;


private Cap mCircleCap = DEFAULT_CIRCLE_CAP;


private RectF mOvalRect = new RectF();


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


@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int w = getMeasuredWidth();
int h = getMeasuredHeight();
int min = Math.min(w, h);
setMeasuredDimension(min, min);
}


@Override
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
// TODO Auto-generated method stub
super.onLayout(changed, left, top, right, bottom);
}


@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);


// 1.绘制外层圆


int radius = getWidth() / 2 - mFirstCircleWidth / 2;
mPaint.setColor(mFirstCircleColor);
mPaint.setStrokeWidth(mFirstCircleWidth);
mPaint.setStyle(Style.STROKE);
canvas.drawCircle(getWidth() / 2, getHeight() / 2, radius, mPaint);
// 2.绘制圆弧


// 1. 圆弧的半径
// int arcRadius = radius;


// 2.开始角度
// int startAngle = mStartProgess;


// 3.当前角度
int currentProgress = mCurrentProgress;


// 4.计算圆弧区域
mOvalRect.left = mFirstCircleWidth / 2;
mOvalRect.top = mFirstCircleWidth / 2;
mOvalRect.right = getWidth() - mFirstCircleWidth / 2;
mOvalRect.bottom = getHeight() - mFirstCircleWidth / 2;


mPaint.setColor(mSecondCircleColor);
mPaint.setStyle(Style.STROKE);
mPaint.setStrokeCap(mCircleCap);


// 5.绘制圆弧
canvas.drawArc(mOvalRect, 0,
(int) (currentProgress * 1.0 / maxProgress * 360), false,
mPaint);
mStartProgess = mCurrentProgress;
// 3.绘制文本


if (isShowProgressText) {
mPaint.reset();
mPaint.setAntiAlias(true);
mPaint.setTextSize(mProgressTextSize);
mPaint.setColor(mProgressTextColor);


String progressText = (int) (mCurrentProgress * 1.0 / maxProgress * 100)
+ "%";


int w = (int) mPaint.measureText(progressText);


int left = (getWidth() - w) / 2;


FontMetrics metrics = mPaint.getFontMetrics();
int top = (getHeight() - (int) Math.ceil(metrics.descent
+ metrics.ascent)) / 2;


canvas.drawText(progressText, left, top, mPaint);
}
}


public synchronized void setProgress(int progress) {
if (progress > maxProgress) {
progress = maxProgress;
}
if (progress < 0) {
progress = DEFAULT_START_PROGRESS;
}
mCurrentProgress = progress;
if (Looper.getMainLooper() == Looper.myLooper()) {
invalidate();
} else {
postInvalidate();
}
}


public int getProgress() {
return mCurrentProgress;
}


public int getmFirstCircleColor() {
return mFirstCircleColor;
}


public int getmFirstCircleWidth() {
return mFirstCircleWidth;
}


public int getmSecondCircleColor() {
return mSecondCircleColor;
}


public int getMaxProgress() {
return maxProgress;
}


public int getmStartProgess() {
return mStartProgess;
}


public int getmProgressTextColor() {
return mProgressTextColor;
}


public int getmProgressTextSize() {
return mProgressTextSize;
}


public Paint getmPaint() {
return mPaint;
}


public int getmCurrentProgress() {
return mCurrentProgress;
}


public RectF getmOvalRect() {
return mOvalRect;
}


@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
// TODO Auto-generated method stub
super.onSizeChanged(w, h, oldw, oldh);
}


public boolean isShowProgressText() {
return isShowProgressText;
}


public void setShowProgressText(boolean isShowProgressText) {
this.isShowProgressText = isShowProgressText;
}


public Cap getmCircleCap() {
return mCircleCap;
}


public void setmCircleCap(Cap mCircleCap) {
this.mCircleCap = mCircleCap;
}


public void setmFirstCircleColor(int mFirstCircleColor) {
this.mFirstCircleColor = mFirstCircleColor;
}


public void setmFirstCircleWidth(int mFirstCircleWidth) {
this.mFirstCircleWidth = mFirstCircleWidth;
}


public void setmSecondCircleColor(int mSecondCircleColor) {
this.mSecondCircleColor = mSecondCircleColor;
}


public void setMaxProgress(int maxProgress) {
this.maxProgress = maxProgress;
}


public void setmStartProgess(int mStartProgess) {
this.mStartProgess = mStartProgess;
}


public void setmProgressTextColor(int mProgressTextColor) {
this.mProgressTextColor = mProgressTextColor;
}


public void setmProgressTextSize(int mProgressTextSize) {
this.mProgressTextSize = mProgressTextSize;
}


public void setmCurrentProgress(int mCurrentProgress) {
this.mCurrentProgress = mCurrentProgress;
}


public CircleProgress(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
// TODO Auto-generated constructor stub
TypedArray typedArray = context.obtainStyledAttributes(attrs,
R.styleable.CircleProgress);
for (int i = 0; i < typedArray.getIndexCount(); i++) {
switch (typedArray.getIndex(i)) {
case R.styleable.CircleProgress_firstCircleColor:
mFirstCircleColor = typedArray.getColor(i,
DEFAULT_FIRST_CIRCLE_COLOR);
break;
case R.styleable.CircleProgress_firstCircleWidth:
mFirstCircleWidth = (int) typedArray.getDimension(i,
dipTopx(DEFAULT_FIRST_CIRCLE_WIDTH));
break;
case R.styleable.CircleProgress_secondCircleColor:
mSecondCircleColor = typedArray.getColor(i,
DEFAULT_SECOND_CIRLCE_COLOR);
break;
case R.styleable.CircleProgress_maxProgress:
maxProgress = typedArray.getInteger(i, DEFAULT_MAX_PROGRESS);
break;
case R.styleable.CircleProgress_startProgress:
mStartProgess = typedArray
.getInteger(i, DEFAULT_START_PROGRESS);
break;
case R.styleable.CircleProgress_progressTextColor:
mProgressTextColor = typedArray.getColor(i,
DEFAULT_PROGRESS_TEXT_COLOR);


break;
case R.styleable.CircleProgress_progressTextSize:
int textSize = (int) typedArray.getDimension(i,
DEFAULT_PROGRESS_TEXT_SIZE);
mProgressTextSize = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_PX, textSize, getResources()
.getDisplayMetrics());


break;
case R.styleable.CircleProgress_isShowProgressText:
isShowProgressText = typedArray.getBoolean(i,
DEFAULT_IS_SHOW_PROGRESS_TEXT);
break;
case R.styleable.CircleProgress_circleCap:
int index = typedArray.getInt(i, 0);
switch (index) {
case BUTT_CAP:
mCircleCap = Cap.BUTT;
break;
case SQUARE_CAP:
mCircleCap = Cap.SQUARE;
break;
case ROUND_CAP:
mCircleCap = Cap.ROUND;
break;
default:
break;
}
break;
default:
break;
}
}


typedArray.recycle();
mPaint = new Paint();
mPaint.setAntiAlias(true);


}


public CircleProgress(Context context) {
super(context);
// TODO Auto-generated constructor stub
}


public int dipTopx(int dip) {
int density = (int) getResources().getDisplayMetrics().density;
return (int) (dip * density + 0.5);
}
}


上面的注释写的比较详细了,就不一句句分析代码了.核心方法是onDraw方法。希望各位fork,同时希望各位提出好的建议。







评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值