本文實現自定義半三環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