项目中有一个圆形进度条的效果,写下实现过程做记录
public class CircleProgress extends View {
public CircleProgressView(Context context) {
super(context);
}
public CircleProgressView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public CircleProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
public CircleProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
}
public CircleProgress(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CircleProgress);
progressColor = ta.getColor(R.styleable.CircleProgress_progress_color, Color.parseColor("#00E091"));
innerColor = ta.getColor(R.styleable.CircleProgress_inner_color, Color.parseColor("#00E091"));
innerRadius = ta.getDimension(R.styleable.CircleProgress_inner_radius, dp2px(75));
ringColor = ta.getColor(R.styleable.CircleProgress_ring_color, Color.parseColor("#1A00E091"));
ringWidth = ta.getDimension(R.styleable.CircleProgress_ring_width, dp2px(10));
ringRadius = ta.getDimension(R.styleable.CircleProgress_ring_radius, dp2px(100));
text = ta.getString(R.styleable.CircleProgress_text);
textSize = ta.getDimension(R.styleable.CircleProgress_textSize, dp2px(36));
textColor = ta.getColor(R.styleable.CircleProgress_textColor, Color.parseColor("#FFFFFF"));
ta.recycle();
init();
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
//view的宽和高,相对于父布局(用于确定圆心)
int viewWidth = getMeasuredWidth();
int viewHeight = getMeasuredHeight();
mViewCenterX = viewWidth / 2;
mViewCenterY = viewHeight / 2;
mRectF = new RectF(
mViewCenterX - ringRadius,
mViewCenterY - ringRadius,
mViewCenterX + ringRadius,
mViewCenterY + ringRadius
);
}
private void init() {
//圆环渐变的颜色
color[0] = Color.parseColor("#00F2C4");
color[1] = Color.parseColor("#00E091");
progressPaint = new Paint();
progressPaint.setColor(progressColor);
setAntialias(progressPaint);
ringPaint = new Paint();
ringPaint.setColor(ringColor);
setAntialias(ringPaint);
innerPaint = new Paint();
//设置抗锯齿
setAntialias(innerPaint);
textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint.setAntiAlias(true);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//设置线性渐变给画笔,没有在init()中初始化是应为会失效
LinearGradient linearGradient = new LinearGradient(mViewCenterX, mViewCenterY - innerRadius, mViewCenterX, mViewCenterY + innerRadius, color, null, Shader.TileMode.CLAMP);
innerPaint.setShader(linearGradient);
//绘制内部实心圆
canvas.drawCircle(mViewCenterX, mViewCenterY, innerRadius, innerPaint);
//绘制进度显示文字
drawTextWithCenterPoint(canvas, mViewCenterX, mViewCenterY, text, textPaint);
//绘制默认进度条圆环
drawNormalRing(canvas);
//绘制颜色显示圆环
drawColorRing(canvas);
}
/**
* 以中心点绘制文字
*
* @param canvas
* @param centerX
* @param centerY
* @param text
* @param paint
*/
private void drawTextWithCenterPoint(Canvas canvas, int centerX, int centerY, String text, Paint paint) {
if (TextUtils.isEmpty(text)) {
return;
}
paint.setTextSize(textSize);
paint.setColor(textColor);
//获取文本的宽度,但是是一个比较粗略的结果
float textWidth = paint.measureText(text);
//文字度量
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
//得到基线的位置
float baselineY = centerY + (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom;
//绘制
canvas.drawText(text, centerX - textWidth / 2, baselineY, paint);
}
/**
* 画默认圆环
*
* @param canvas
*/
private void drawNormalRing(Canvas canvas) {
Paint ringNormalPaint = new Paint(ringPaint);
ringNormalPaint.setStyle(Paint.Style.STROKE);
ringNormalPaint.setStrokeWidth(ringWidth);
ringNormalPaint.setColor(ringColor);//圆环默认颜色为灰色
canvas.drawArc(mRectF, 0, 360, false, ringNormalPaint);
}
private void drawColorRing(Canvas canvas) {
progressPaint.setStyle(Paint.Style.STROKE);
progressPaint.setStrokeCap(Paint.Cap.ROUND);//使圆弧两头圆滑
progressPaint.setStrokeWidth(ringWidth);
//加上渐变色
// progressPaint.setShader(new SweepGradient(mViewCenterX, mViewCenterX, color, null));
//逆时针旋转90度
canvas.rotate(180, mViewCenterX, mViewCenterY);
canvas.drawArc(mRectF, startAngle, mSelectRing, false, progressPaint);
// progressPaint.setShader(null);
}
public int dp2px(float dpValue) {
final float scale = Resources.getSystem().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
package com.cash.cashlibrary.widget;
import android.animation.ValueAnimator;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import androidx.annotation.Nullable;
import com.cash.cashlibrary.R;
public class CircleProgress extends View {
private static final String TAG = "CircleProgress";
private Paint progressPaint;
private int progressColor;//进度的颜色
//圆环相关
private Paint ringPaint;
private int ringColor;//圆环的颜色
private float ringRadius; //圆环半径
private float ringWidth; //圆环的宽度
//内圆相关
private Paint innerPaint;
private float innerRadius;//内圆的半径
private int innerColor; //内圆的颜色
//文字
private Paint textPaint;
private float textSize;//文字大小
private int textColor; //文字颜色
private String text; //文字
private int progress = 0; //进度
private int maxValue = 100;//最大进度
public CircleProgress(Context context) {
super(context);
init();
}
public CircleProgress(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.CircleProgress);
progressColor = ta.getColor(R.styleable.CircleProgress_progress_color, Color.parseColor("#00E091"));
innerColor = ta.getColor(R.styleable.CircleProgress_inner_color, Color.parseColor("#00E091"));
innerRadius = ta.getDimension(R.styleable.CircleProgress_inner_radius, dp2px(75));
ringColor = ta.getColor(R.styleable.CircleProgress_ring_color, Color.parseColor("#1A00E091"));
ringWidth = ta.getDimension(R.styleable.CircleProgress_ring_width, dp2px(10));
ringRadius = ta.getDimension(R.styleable.CircleProgress_ring_radius, dp2px(100));
text = ta.getString(R.styleable.CircleProgress_text);
textSize = ta.getDimension(R.styleable.CircleProgress_textSize, dp2px(36));
textColor = ta.getColor(R.styleable.CircleProgress_textColor, Color.parseColor("#FFFFFF"));
ta.recycle();
init();
}
public CircleProgress(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public CircleProgress(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
init();
}
/**
* 画默认圆环
*
* @param canvas
*/
private void drawNormalRing(Canvas canvas) {
Paint ringNormalPaint = new Paint(ringPaint);
ringNormalPaint.setStyle(Paint.Style.STROKE);
ringNormalPaint.setStrokeWidth(ringWidth);
ringNormalPaint.setColor(ringColor);//圆环默认颜色为灰色
canvas.drawArc(mRectF, 0, 360, false, ringNormalPaint);
}
/**
* 设置当前值
*
* @param value
*/
public void setValue(int value) {
if (value > maxValue) {
value = maxValue;
}
int start = 0;
int end = value;
startAnimator(start, end, 1000);
}
private int mSelectRing = 90; //要显示的彩色区域(岁数值变化)
private ValueAnimator valueAnimator;
private void startAnimator(int start, int end, long animTime) {
valueAnimator = ValueAnimator.ofInt(start, end);
valueAnimator.setDuration(animTime);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
int i = Integer.parseInt(String.valueOf(animation.getAnimatedValue()));
text = (i + " %");
//每个单位长度占多少度
mSelectRing = (int) (360 * (i / 100f));
invalidate();
}
});
valueAnimator.start();
}
private int color[] = new int[2]; //渐变颜色
private void init() {
//圆环渐变的颜色
color[0] = Color.parseColor("#00F2C4");
color[1] = Color.parseColor("#00E091");
progressPaint = new Paint();
progressPaint.setColor(progressColor);
setAntialias(progressPaint);
ringPaint = new Paint();
ringPaint.setColor(ringColor);
setAntialias(ringPaint);
innerPaint = new Paint();
// innerPaint.setColor(innerColor);
setAntialias(innerPaint);
textPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
textPaint.setAntiAlias(true);
}
//防止边缘锯齿
private void setAntialias(Paint paint) {
paint.setAntiAlias(true);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
LinearGradient linearGradient = new LinearGradient(mViewCenterX, mViewCenterY - innerRadius, mViewCenterX, mViewCenterY + innerRadius, color, null, Shader.TileMode.CLAMP);
innerPaint.setShader(linearGradient);
canvas.drawCircle(mViewCenterX, mViewCenterY, innerRadius, innerPaint);
drawTextWithCenterPoint(canvas, mViewCenterX, mViewCenterY, text, textPaint);
drawNormalRing(canvas);
drawColorRing(canvas);
}
private void drawColorRing(Canvas canvas) {
progressPaint.setStyle(Paint.Style.STROKE);
progressPaint.setStrokeCap(Paint.Cap.ROUND);//使圆弧两头圆滑
progressPaint.setStrokeWidth(ringWidth);
//加上渐变色
// progressPaint.setShader(new SweepGradient(mViewCenterX, mViewCenterX, color, null));
//逆时针旋转90度
canvas.rotate(180, mViewCenterX, mViewCenterY);
canvas.drawArc(mRectF, startAngle, mSelectRing, false, progressPaint);
// progressPaint.setShader(null);
}
private float startAngle = 0;
/**
* 以中心点绘制文字
*
* @param canvas
* @param centerX
* @param centerY
* @param text
* @param paint
*/
private void drawTextWithCenterPoint(Canvas canvas, int centerX, int centerY, String text, Paint paint) {
if (TextUtils.isEmpty(text)) {
return;
}
paint.setTextSize(textSize);
paint.setColor(textColor);
//获取文本的宽度,但是是一个比较粗略的结果
float textWidth = paint.measureText(text);
//文字度量
Paint.FontMetrics fontMetrics = paint.getFontMetrics();
//得到基线的位置
float baselineY = centerY + (fontMetrics.bottom - fontMetrics.top) / 2 - fontMetrics.bottom;
//绘制
canvas.drawText(text, centerX - textWidth / 2, baselineY, paint);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private int mViewCenterX; //view宽的中心点(可以暂时理解为圆心)
private int mViewCenterY;
private RectF mRectF; //圆环的矩形区域
@SuppressLint("DrawAllocation")
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
//view的宽和高,相对于父布局(用于确定圆心)
int viewWidth = getMeasuredWidth();
int viewHeight = getMeasuredHeight();
mViewCenterX = viewWidth / 2;
mViewCenterY = viewHeight / 2;
mRectF = new RectF(
mViewCenterX - ringRadius,
mViewCenterY - ringRadius,
mViewCenterX + ringRadius,
mViewCenterY + ringRadius
);
}
public int dp2px(float dpValue) {
final float scale = Resources.getSystem().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}