本文实现自定义半三环View效果。主要目的是总结实现过程当中的思路以及一些须要注意的地方。 首先,效果图:java
onMeasurecanvas
setMeasuredDimensionide
Canvas#drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)post
onDrawthis
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 根据父控件传递的widthMeasureSpec和heightMeasureSpec调用MeasureSpec.getSize测量自身宽高
int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
int measureHeight = MeasureSpec.getSize(heightMeasureSpec);
int finalWidth = measureWidth;
int finalHeight = measureHeight;
// 根据自身宽高从新计算新的宽高,使新的宽高比为2:1
if (measureWidth >= measureHeight * 2) {
finalWidth = measureHeight * 2;
} else {
finalHeight = measureWidth / 2;
}
// 设置View新的宽高
setMeasuredDimension(finalWidth, finalHeight);
}
复制代码
/** * 绘制圆弧 * @param canvas * @param progress 进度 * @param color 进度颜色 * @param radius 圆弧半径 */
private void drawArc(Canvas canvas, float progress, int color, float radius){
// 圆心
mXCenter = getWidth() / 2;
mYCenter = getHeight() ;
mPaint.setColor(mBackgroundArcColor);
// 构造边界矩形
RectF oval = new RectF();
oval.left = (mXCenter - radius);
oval.top = (mYCenter - radius);
oval.right = mXCenter + radius;
oval.bottom = radius * 2 + (mYCenter - radius);
//绘制圆弧背景
canvas.drawArc(oval, -180, 180, false, mPaint);
//绘制圆弧进度
float showDegree = progress / 100 * 180;
mPaint.setColor(color);
canvas.drawArc(oval, -180, showDegree, false, mPaint);
}
复制代码
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 初始半径
float originalRadius = getWidth() * .5f;
// 画笔半宽
float halfArcStokeWidth = mArcStrokeWidth * .5f;
// 外圆环半径=初始半径-画笔半宽
float outSideArcRadius = originalRadius - halfArcStokeWidth;
drawArc(canvas, mOutsideProgress, mOutsideArcColor, outSideArcRadius);
// 中圆环半径=外圆的半径-圆环偏移值-画笔半宽
float middleArcRadius = outSideArcRadius - mArcOffset - halfArcStokeWidth;
drawArc(canvas, mMiddleProgress, mMiddleArcColor, middleArcRadius);
// 内圆环半径=中圆的半径-圆环偏移值-画笔半宽
float insideArcRadius = middleArcRadius - mArcOffset - halfArcStokeWidth;
drawArc(canvas, mInsideProgress, mInsideArcColor, insideArcRadius);
}
复制代码
ThreeArcView.javaspa
public class ThreeArcView extends View {
//圆弧画笔
private Paint mPaint;
//背景圆环颜色
private int mBackgroundArcColor;
//外圆环颜色
private int mOutsideArcColor;
//中圆环颜色
private int mMiddleArcColor;
//内圆环颜色
private int mInsideArcColor;
//外圆展现弧度
private float mOutsideProgress;
//中圆展现弧度
private float mMiddleProgress;
//内圆展现弧度
private float mInsideProgress;
//圆弧宽度
private float mArcStrokeWidth;
//圆偏移值
private float mArcOffset;
// 圆心x坐标
private int mXCenter;
// 圆心y坐标
private int mYCenter;
public ThreeArcView(Context context) {
this(context, null);
}
public ThreeArcView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public ThreeArcView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initAttrs(context, attrs);
initVariable();
}
private void initAttrs(Context context, AttributeSet attrs) {
TypedArray typeArray = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ThreeArcView, 0, 0);
mArcStrokeWidth = typeArray.getDimension(R.styleable.ThreeArcView_ts_strokeWidth, dp2px(context, 20));
// 圆环背景颜色
mBackgroundArcColor = typeArray.getColor(R.styleable.ThreeArcView_ts_bgArcColor, 0xFFFFFFFF);
// 圆环颜色
mOutsideArcColor = typeArray.getColor(R.styleable.ThreeArcView_ts_outsideBgColor, 0xFFFFFFFF);
mMiddleArcColor = typeArray.getColor(R.styleable.ThreeArcView_ts_middleBgColor, 0xFFFFFFFF);
mInsideArcColor = typeArray.getColor(R.styleable.ThreeArcView_ts_insideBgColor, 0xFFFFFFFF);
// 圆进度
mOutsideProgress = typeArray.getFloat(R.styleable.ThreeArcView_ts_outsideProgress, 0f);
mMiddleProgress = typeArray.getFloat(R.styleable.ThreeArcView_ts_middleProgress, 0f);
mInsideProgress = typeArray.getFloat(R.styleable.ThreeArcView_ts_insideProgress, 0f);
// 圆环偏移值
mArcOffset = typeArray.getDimension(R.styleable.ThreeArcView_ts_radiusOffset, dp2px(context, 20));
typeArray.recycle();
// 偏移值不能小于画笔宽度的一半,不然会发生覆盖
if (mArcOffset < mArcStrokeWidth / 2){
mArcOffset = mArcStrokeWidth / 2;
}
}
private void initVariable() {
//背景圆弧画笔设置
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mArcStrokeWidth);
mPaint.setStrokeCap(Paint.Cap.ROUND);//开启显示边缘为圆形
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 分别获取指望的宽度和高度,并取其中较小的尺寸做为该控件的宽和高
int measureWidth = MeasureSpec.getSize(widthMeasureSpec);
int measureHeight = MeasureSpec.getSize(heightMeasureSpec);
//裁剪出一个 (宽:高) = (2:1) 的矩形
int finalWidth = measureWidth;
int finalHeight = measureHeight;
if (measureWidth >= measureHeight * 2) {
finalWidth = measureHeight * 2;
} else {
finalHeight = measureWidth / 2;
}
setMeasuredDimension(finalWidth, finalHeight);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 初始半径
float originalRadius = getWidth() * .5f;
// 画笔半宽
float halfArcStokeWidth = mArcStrokeWidth * .5f;
// 外圆环半径=初始半径-画笔半宽
float outSideArcRadius = originalRadius - halfArcStokeWidth;
drawArc(canvas, mOutsideProgress, mOutsideArcColor, outSideArcRadius);
// 中圆环半径=外圆的半径-圆环偏移值-画笔半宽
float middleArcRadius = outSideArcRadius - mArcOffset - halfArcStokeWidth;
drawArc(canvas, mMiddleProgress, mMiddleArcColor, middleArcRadius);
// 内圆环半径=中圆的半径-圆环偏移值-画笔半宽
float insideArcRadius = middleArcRadius - mArcOffset - halfArcStokeWidth;
drawArc(canvas, mInsideProgress, mInsideArcColor, insideArcRadius);
}
/** * 绘制圆弧 * @param canvas * @param progress 进度 * @param color 进度颜色 * @param radius 圆弧半径 */
private void drawArc(Canvas canvas, float progress, int color, float radius){
// 圆心
mXCenter = getWidth() / 2;
mYCenter = getHeight() ;
mPaint.setColor(mBackgroundArcColor);
// 构造边界矩形
RectF oval = new RectF();
oval.left = (mXCenter - radius);
oval.top = (mYCenter - radius);
oval.right = mXCenter + radius;
oval.bottom = radius * 2 + (mYCenter - radius);
//绘制圆弧背景
canvas.drawArc(oval, -180, 180, false, mPaint);
//绘制圆弧进度
float showDegree = progress / 100 * 180;
mPaint.setColor(color);
canvas.drawArc(oval, -180, showDegree, false, mPaint);
}
private void setOutSideProgress(float progress){
this.mOutsideProgress = progress;
postInvalidate();
}
private void setMiddleProgress(float progress){
this.mMiddleProgress = progress;
postInvalidate();
}
private void setInsideProgress(float progress){
this.mInsideProgress = progress;
postInvalidate();
}
public void setProgress(float outSideProgress, float middleProgress, float insideProgress) {
mOutsideProgress = outSideProgress;
mMiddleProgress = middleProgress;
mInsideProgress = insideProgress;
postInvalidate();
}
public int dp2px(Context context, float dipValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dipValue * scale + 0.5f);
}
public int sp2px(Context context, float spValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (spValue * fontScale + 0.5f);
}
public int px2sp(Context context, float pxValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (pxValue / fontScale + 0.5f);
}
}
复制代码
styes.xmlrest
<declare-styleable name="ThreeArcView">
<!-- 画笔宽度 -->
<attr name="ts_strokeWidth" format="dimension" />
<!-- 圆弧背景色 -->
<attr name="ts_bgArcColor" format="color" />
<!-- 外圆进度颜色 -->
<attr name="ts_outsideBgColor" format="color" />
<!-- 中圆进度颜色 -->
<attr name="ts_middleBgColor" format="color" />
<!-- 内圆进度颜色 -->
<attr name="ts_insideBgColor" format="color" />
<!-- 外圆进度 -->
<attr name="ts_outsideProgress" format="float" />
<!-- 中圆进度 -->
<attr name="ts_middleProgress" format="float" />
<!-- 内圆进度 -->
<attr name="ts_insideProgress" format="float" />
<!-- 圆偏移值 -->
<attr name="ts_radiusOffset" format="dimension" />
</declare-styleable>
复制代码
OK,本文到此结束,若发现问题,欢迎一块儿留言一块儿探讨,感谢~code