自定义圆环形进度条实现
Posted 我叫白小飞
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自定义圆环形进度条实现相关的知识,希望对你有一定的参考价值。
最近项目里边要用进度条,进度条中间展示进度,底部展示label,因为这个组件用的地方多,所以我就直接封装了一个通用组件。
先看一下效果图:
功能有:
- 圆环的颜色和进度可以自定义;
- 中间文字可以自定义;
- 可以自定义圆环的宽度;
- 可以设置底部文字(文字内容、大小和textStyle);
- 提供设置进度的接口;
- 可以设置进度的最大值;
下边开始编码:
- 首先继承定义一个类继承自View,因为我们需要提供一些可配置的自定义属性:
public class CircleProgress extends View
private final Paint mPaint; // 画笔
private final RectF mRectF;
private final Rect mRect;
private final Paint mBottomPaint; // 绘制底部文字
private int mCurrent; // 当前进度
private int mMax; // 最大进度
private int mWidth; // 当前view设置的宽度
public CircleProgress(Context context)
this(context,null);
public CircleProgress(Context context, @Nullable AttributeSet attrs)
this(context, attrs,0);
public CircleProgress(Context context, @Nullable AttributeSet attrs, int defStyleAttr)
super(context, attrs, defStyleAttr);
initAttr(context,attrs);
mPaint = new Paint();
mBottomPaint = new Paint();
mBottomPaint.setAntiAlias(true);
mPaint.setAntiAlias(true);
mRectF = new RectF();
mRect = new Rect();
- 自定义属性,在attr.xml中新建一个declare-styleable,并命名为:CircleProgress
<!-- 圆环进度条 -->
<declare-styleable name="CircleProgress">
<attr name="max_progress" format="integer"/>
<attr name="arc_bg_color" format="color"/>
<attr name="arc_color" format="color"/>
<attr name="arc_width" format="dimension"/>
<attr name="mid_text_size" format="dimension"/>
<attr name="bottom_text_size" format="dimension"/>
<attr name="bottom_text" format="string" localization="suggested"/>
<attr name="textStyle">
<flag name="normal" value="0" />
<flag name="bold" value="1" />
</attr>
</declare-styleable>
- 然后我们在initAttr()方法中解析这些属性,解析出来的属性,后边在绘制的时候需要用到:
private void initAttr(Context context, AttributeSet attrs)
TypedArray attributes = context.obtainStyledAttributes(attrs,R.styleable.CircleProgress);
mMax = attributes.getInteger(R.styleable.CircleProgress_max_progress, 100);
mCircleBGColor = attributes.getColor(R.styleable.CircleProgress_arc_bg_color,context.getResources().getColor(R.color.color_d1, null));
mCircleColor = attributes.getColor(R.styleable.CircleProgress_arc_color,context.getResources().getColor(R.color.colorRed, null));
mArcWidth = attributes.getDimensionPixelOffset(R.styleable.CircleProgress_arc_width,SizeUtils.dp2px(20));
mPercentTextSize = attributes.getDimensionPixelOffset(R.styleable.CircleProgress_mid_text_size,SizeUtils.sp2px(12));
mBottomTextSize = attributes.getDimensionPixelOffset(R.styleable.CircleProgress_bottom_text_size,SizeUtils.sp2px(14));
mBottomTextId = attributes.getResourceId(R.styleable.CircleProgress_bottom_text,0);
mBottomText = attributes.getText(R.styleable.CircleProgress_bottom_text).toString();
mBottomTextType = attributes.getInt(R.styleable.CircleProgress_textStyle,0);
attributes.recycle();
- 解析完属性之后,就可以开始绘制了,绘制主要按照顺序绘制,我们先绘制圆环,在绘制百分比,然后绘制底部文字:
@Override
protected void onDraw(Canvas canvas)
super.onDraw(canvas);
//绘制圆形
//设置为空心圆,如果不理解绘制弧线是什么意思就把这里的属性改为“填充”,跑一下瞬间就明白了
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setAntiAlias(true);
//设置圆弧的宽度(圆环的宽度)
mPaint.setStrokeWidth(mArcWidth);
mPaint.setColor(mCircleBGColor);
//大圆的半径
float bigCircleRadius = mWidth / 2;
// 小圆的半径
float smallCircleRadius = bigCircleRadius - mArcWidth;
// 绘制小圆
canvas.drawCircle(bigCircleRadius,bigCircleRadius,smallCircleRadius,mPaint);
mPaint.setColor(mCircleColor);
mRectF.set(mArcWidth,mArcWidth,mWidth - mArcWidth,mWidth - mArcWidth);
// 绘制圆弧
canvas.drawArc(mRectF,90f,mCurrent * 360f / mMax, false, mPaint);
// 计算百分比
String percent = mCurrent * 100 / mMax + "%";
mPaint.setStrokeWidth(0);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setTextSize(mPercentTextSize);
mPaint.getTextBounds(percent, 0, percent.length(), mRect);
mPaint.setColor(mCircleColor);
// 绘制百分比
canvas.drawText(percent,bigCircleRadius- mRect.width() / 2, bigCircleRadius + mRect.height() / 2, mPaint);
// 绘制底部文字
if (!TextUtils.isEmpty(mBottomText))
mBottomPaint.setStrokeWidth(0);
mBottomPaint.setTextSize(mBottomTextSize);
mBottomPaint.getTextBounds(mBottomText.toString(),0, mBottomText.toString().length(),mRect);
mBottomPaint.setColor(Color.BLACK);
if (mBottomTextType == 1)
Typeface tf = Typeface.DEFAULT_BOLD;
mBottomPaint.setTypeface(tf);
canvas.drawText(mBottomText.toString(),bigCircleRadius - mRect.width() / 2f, mWidth + mRect.height(), mBottomPaint);
else if(mBottomTextId > 0)
String bottomText = getResources().getString(mBottomTextId);
mBottomPaint.setStrokeWidth(0);
mBottomPaint.setTextSize(mBottomTextSize);
mBottomPaint.getTextBounds(bottomText,0, bottomText.length(),mRect);
mBottomPaint.setColor(Color.BLACK);
if (mBottomTextType == 1)
Typeface tf = Typeface.DEFAULT_BOLD;
mBottomPaint.setTypeface(tf);
canvas.drawText(bottomText,bigCircleRadius - mRect.width() / 2f, mWidth + mRect.height(), mBottomPaint);
- 编译之后就可以在布局文件中使用了:
<com.towngas.top.commonlibrary.widget.CircleProgress
android:id="@+id/cp_timeliness_patrol"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="match_parent"
app:max_progress="100"
app:arc_width="@dimen/dp_12"
app:arc_bg_color="#FBCCA0"
app:arc_color="#FBCCA0"
app:bottom_text_size="@dimen/sp_14"
app:textStyle="bold"
app:bottom_text="下载"/>
完整代码:
public class CircleProgress extends View
private final Paint mPaint; // 画笔
private final RectF mRectF;
private final Rect mRect;
private final Paint mBottomPaint; // 绘制底部文字
private int mCurrent; // 当前进度
private int mMax; // 最大进度
private int mWidth; // 当前view设置的宽度
//圆弧(也可以说是圆环)的宽度
private float mArcWidth;
private int mCircleBGColor; // 自定义圆环背景color
private int mCircleColor; // 自定义圆环clolr
private int mBottomTextId = Resources.ID_NULL; // 底部文字
private CharSequence mBottomText; //底部文字
private float mPercentTextSize; // 百分比文字大小
private float mBottomTextSize; // 底部文字大小
private int mBottomTextType; // 字体样式
public CircleProgress(Context context)
this(context,null);
public CircleProgress(Context context, @Nullable AttributeSet attrs)
this(context, attrs,0);
public CircleProgress(Context context, @Nullable AttributeSet attrs, int defStyleAttr)
super(context, attrs, defStyleAttr);
initAttr(context,attrs);
mPaint = new Paint();
mBottomPaint = new Paint();
mBottomPaint.setAntiAlias(true);
mPaint.setAntiAlias(true);
mRectF = new RectF();
mRect = new Rect();
private void initAttr(Context context, AttributeSet attrs)
TypedArray attributes = context.obtainStyledAttributes(attrs,R.styleable.CircleProgress);
mMax = attributes.getInteger(R.styleable.CircleProgress_max_progress, 100);
mCircleBGColor = attributes.getColor(R.styleable.CircleProgress_arc_bg_color,context.getResources().getColor(R.color.color_d1, null));
mCircleColor = attributes.getColor(R.styleable.CircleProgress_arc_color,context.getResources().getColor(R.color.colorRed, null));
mArcWidth = attributes.getDimensionPixelOffset(R.styleable.CircleProgress_arc_width,SizeUtils.dp2px(20));
mPercentTextSize = attributes.getDimensionPixelOffset(R.styleable.CircleProgress_mid_text_size,SizeUtils.sp2px(12));
mBottomTextSize = attributes.getDimensionPixelOffset(R.styleable.CircleProgress_bottom_text_size,SizeUtils.sp2px(14));
mBottomTextId = attributes.getResourceId(R.styleable.CircleProgress_bottom_text,0);
mBottomText = attributes.getText(R.styleable.CircleProgress_bottom_text).toString();
mBottomTextType = attributes.getInt(R.styleable.CircleProgress_textStyle,0);
attributes.recycle();
/**
* 设置当前进度
* @param current
*/
public void SetCurrent(int current)
this.mCurrent = current;
invalidate();
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//getMeasuredWidth获取的是view的原始大小,也就是xml中配置或者代码中设置的大小
//getWidth获取的是view最终显示的大小,这个大小不一定等于原始大小
mWidth = getMeasuredWidth();
@Override
protected void onDraw(Canvas canvas)
super.onDraw(canvas);
//绘制圆形
//设置为空心圆,如果不理解绘制弧线是什么意思就把这里的属性改为“填充”,跑一下瞬间就明白了
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setAntiAlias(true);
//设置圆弧的宽度(圆环的宽度)
mPaint.setStrokeWidth(mArcWidth);
mPaint.setColor(mCircleBGColor);
//大圆的半径
float bigCircleRadius = mWidth / 2;
// 小圆的半径
float smallCircleRadius = bigCircleRadius - mArcWidth;
// 绘制小圆
canvas.drawCircle(bigCircleRadius,bigCircleRadius,smallCircleRadius,mPaint);
mPaint.setColor(mCircleColor);
mRectF.set(mArcWidth,mArcWidth,mWidth - mArcWidth,mWidth - mArcWidth);
// 绘制圆弧
canvas.drawArc(mRectF,90f,mCurrent * 360f / mMax, false, mPaint);
// 计算百分比
String percent = mCurrent * 100 / mMax + "%";
mPaint.setStrokeWidth(0);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setTextSize(mPercentTextSize);
mPaint.getTextBounds(percent, 0, percent.length(), mRect);
mPaint.setColor(mCircleColor);
// 绘制百分比
canv以上是关于自定义圆环形进度条实现的主要内容,如果未能解决你的问题,请参考以下文章