一.效果图(文字是自己UI绘制的,此自定义VIew是双圆)
二.在styles在配置declare-styleable
<declare-styleable name="CircleProgressView">
//背景颜色
<attr name="outerColor" format="color"/>
//圆弧颜色
<attr name="innerColor" format="color"/>
//弧宽度
<attr name="borderWidth" format="dimension"/>
//渐变色起始颜色
<attr name="foreStartColor" format="color" />
//渐变色结束颜色
<attr name="foreEndColor" format="color" />
</declare-styleable>
三.绘制自定义VIew
public class CircleProgressView extends View {
private static final String TAG = CircleProgressView.class.getSimpleName();
//#EFEFEF
//#47C496
private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
LinearGradient gradient;
//画笔宽度,线段长度,最后一条大线条的长度 比其他线段长的长度
private int strokeWidth = 3, lineLength =40, maxLineLength = 0;
//绘制文本距离圆
private int txtMargin = 10;
//中心点坐标
private int centerX, centerY;
//内圆半径,外圆半径
private int innerRadius, outRadius;
//绘制文本
private String leftText = "", rightText = "";
//绘制文本的字体大小
private int textSize = 25;
//背景 or 进度条颜色
private int colorBackground = Color.parseColor("#0FD4DEFA");
private int colorProgress = Color.parseColor("#18C8C7");
private int colorText = Color.parseColor("#999999");
float fullAngle = 180f;
float cutAngle = 90f;
//每个线段相隔的宽度
private static final int perAngle = 6;
private int startAngle = 0;
private RectF mRectF;
//背景颜色
private int mOuterColor = Color.GRAY;
//圆弧颜色
private int mInterColor = Color.BLUE;
//弧宽度
private int mBorderWidth = 14; //10px
//背景画笔
private Paint mOuterPaint;
//圆弧颜色
private Paint mInnerPaint;
//总流量
private int mMaxStep = 0;
//剩余流量
private int mCurrentStep = 0;
//是否使用渐变
private boolean useGradient = true;
//前景色起始颜色
private int foreStartColor;
//前景色结束颜色
private int foreEndColcor;
public CircleProgressView(Context context) {
super(context);
initPaint(context, null);
}
public CircleProgressView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initPaint(context, attrs);
initAttrs(context, attrs);
initVariable();
}
private void initAttrs(Context context, AttributeSet attrs){
//获取xml里的属性值
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.CircleProgressView);
mOuterColor = array.getColor(R.styleable.CircleProgressView_outerColor, mOuterColor);
mInterColor = array.getColor(R.styleable.CircleProgressView_innerColor, mInterColor);
mBorderWidth = (int) array.getDimension(R.styleable.CircleProgressView_borderWidth, mBorderWidth);
foreStartColor = array.getColor(R.styleable.CircleProgressView_foreStartColor, Color.RED);
foreEndColcor = array.getColor(R.styleable.CircleProgressView_foreEndColor, Color.BLUE);
//释放资源
array.recycle();
}
private void initVariable() {
//初始化背景画笔
mOuterPaint = new Paint();
mOuterPaint.setAntiAlias(true);
mOuterPaint.setColor(mOuterColor);
mOuterPaint.setStrokeWidth(mBorderWidth);//width 是弧的内外扩散的
mOuterPaint.setStyle(Paint.Style.STROKE);//Fill画笔实心,Stroke描边
mOuterPaint.setStrokeCap(Paint.Cap.ROUND);
//初始化圆弧画笔
mInnerPaint = new Paint();
mInnerPaint.setAntiAlias(true);
mInnerPaint.setColor(mInterColor);
mInnerPaint.setStrokeWidth(mBorderWidth);//width 是弧的内外扩散的
mInnerPaint.setStyle(Paint.Style.STROKE);//Fill画笔实心,Stroke描边
mInnerPaint.setStrokeCap(Paint.Cap.ROUND);
}
private void initPaint(Context context, AttributeSet attrs) {
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setTextSize(textSize);
paint.setStrokeWidth(strokeWidth);
paint.setTextAlign(Paint.Align.CENTER);
// paint.setColor(colorBackground);
}
public CircleProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initPaint(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
float endAngle = (float) mCurrentStep / mMaxStep * 180;
Log.i(TAG,"mCurrentStep"+ mCurrentStep + "mMaxStep" + mMaxStep + "endAngle" + endAngle);
drawCircle(startAngle, endAngle, canvas, paint);
drawOut(canvas);
}
private void drawOut(Canvas canvas) {
int center = getWidth() / 2;
int radius = getWidth() / 2 - mBorderWidth / 2;
RectF rectF = new RectF(center-radius, center-radius, center+radius, center+radius);
//绘制背景圆弧
canvas.drawArc(rectF, 180, 180, false, mOuterPaint);
if (mMaxStep == 0) {
return;
}
float sweepAngle = (float) mCurrentStep / mMaxStep;
//绘制圆弧画笔
canvas.drawArc(rectF, 180, sweepAngle * 180, false, mInnerPaint);
}
private void drawCircle(float startAngle, float endAngle, Canvas canvas, Paint paint) {
for (float i = startAngle; i <= fullAngle - startAngle; i = i + perAngle) {
//-12.-6,0,6....180,186,192
//得出坐标
int startM, startN, endM, endN, startX, startY, endX, endY;
int startPaintRadius = innerRadius;
int endPaintRadius = outRadius;
float currentAngle = i;
Log.i(TAG,"currentAngle: " + currentAngle + " startPaintRadius: " + startPaintRadius + " endPaintRadius: " +endPaintRadius + " i: " + i);
if (i <= 0) {
currentAngle = Math.abs(i);
} else if (currentAngle > fullAngle) {
currentAngle = i - fullAngle;
}
//当前进度=结束进度
if (i == endAngle) {
startPaintRadius = innerRadius;
endPaintRadius = outRadius ;
}
//起始点
double angleSin = Math.sin(Math.PI * (Math.abs(currentAngle) / fullAngle));
//起始点 高度 宽度
startM = (int) (angleSin * startPaintRadius);
startN = (int) Math.sqrt(Math.pow(startPaintRadius, 2) - Math.pow(startM, 2));
//结束点 高度 宽度
endM = (int) (angleSin * endPaintRadius);
endN = (int) Math.sqrt(Math.pow(endPaintRadius, 2) - Math.pow(endM, 2));
// Log.i(TAG, startM + "," + startN + "," + endM + "," + endN);
//获得起始点和结束点的坐标
if (i < 0) {
//第三象限
startX = centerX - startN;
endX = centerX - endN;
startY = centerY + startM;
endY = centerY + endM;
Log.i(TAG,"startX3 "+ startX + " endX3: "+ endX + " startY3: " + startY + "endY3: " + endY);
} else if (i > fullAngle) {
//第二象限
startX = centerX + startN;
endX = centerX + endN;
startY = centerY + startM;
endY = centerY + endM;
Log.i(TAG,"startX2 "+ startX + " endX2: "+ endX + " startY2: " + startY + "endY2: " + endY);
} else {
if (i < cutAngle) {
//第四象限
startX = centerX - startN;
endX = centerX - endN;
startY = centerY - startM;
endY = centerY - endM;
Log.i(TAG,"startX4 "+ startX + " endX4: "+ endX + " startY4: " + startY + "endY4: " + endY);
} else {
//第一象限
startX = centerX + startN;
endX = centerX + endN;
startY = centerY - startM;
endY = centerY - endM;
Log.i(TAG,"startX1 "+ startX + " endX1: "+ endX + " startY1: " + startY + "endY1: " + endY);
}
}
//设置线条绘制颜色
if (i <= endAngle) {
paint.setShader(gradient);
// paint.setColor(colorProgress);
} else {
paint.setShader(null);
paint.setColor(colorBackground);
}
canvas.drawLine(startX, startY, endX, endY, paint);
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
//画笔设置渐变色
initRect(w,h);
if (useGradient) {
LinearGradient gradient = new LinearGradient(0, 0, w, h, foreStartColor, foreEndColcor, Shader.TileMode.CLAMP);
this.gradient = gradient;
mInnerPaint.setShader(gradient);
} else {
mInnerPaint.setColor(mInterColor);
}
}
private void initRect(int width, int height) {
mRectF = new RectF(0, 0, width, height);
paint.setShader(new LinearGradient(0, 0, mRectF.right, 0,
Color.GREEN, Color.RED, Shader.TileMode.CLAMP));
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width > height ? height : width, width > height ? height : width);
innerRadius = (getMeasuredWidth() - lineLength * 2 ) / 2 ;
outRadius = 11 + innerRadius;
Log.i(TAG,"内圈半径:" + innerRadius + ",外圈半径:" + outRadius);
centerX = 187 + maxLineLength;
centerY = 187 + maxLineLength;
Log.i(TAG,"中心坐标:(x=" + centerX + ",y=" + centerY + ")");
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (heightMode == MeasureSpec.AT_MOST) {
double angleSin = Math.sin(Math.PI * (Math.abs(startAngle) / fullAngle));
int endPaintRadius = outRadius + maxLineLength;
height = (int) (endPaintRadius + angleSin * endPaintRadius);
setMeasuredDimension(widthMeasureSpec, height);
}
}
public synchronized void setStepMax(int mMaxStep) {
this.mMaxStep = mMaxStep;
}
public synchronized void setCurrentStep(int mCurrentStep) {
this.mCurrentStep = mCurrentStep;
invalidate();
}
}
四.使用
1.UI绘制
<com.text.ui.CircleProgressView
android:id="@+id/circle_progress"
android:layout_width="374px"
android:layout_height="374px"
android:layout_marginTop="@dimen/y34"
android:layout_marginStart="@dimen/x17"
app:foreStartColor="#7D78FF"
app:foreEndColor="#00DFFF"
app:outerColor= "@color/btn_weak_color" />
2.代码使用
circleProgressView.setStepMax(24);
circleProgressView.setCurrentStep(12);