
/**
* 双弧形进度条
*/
public class DoubleArcProgressBar extends View {
private final static int ANIMATOR_DURATION = 500;
private float mStartAngle;
private float mAngle;
private Paint mInsideArcPaint;
private int mInsideArcColor;
private int mInsideProgressArcColor;
private int mInsideArcWidth;
private int mInsideRadius;
private int mInsideValue;
private int mInsideMax;
private RectF mInsideRect;
private Paint mExtArcPaint;
private int mExtArcColor;
private int mExtProgressArcColor;
private int mExtArcWidth;
private int mExtRadius;
private int mExtValue;
private int mExtMax;
private RectF mExtRect;
private Paint mText1Paint;
private int mText1Color;
private int mText1Size;
private String mText1;
private Paint mText2Paint;
private int mText2Color;
private int mText2Size;
private String mText2;
private Paint mText3Paint;
private int mText3Color;
private int mText3Size;
private String mText3;
private Paint mText4Paint;
private int mText4Color;
private int mText4Size;
private String mText4;
private Rect mRectText;
private PaintFlagsDrawFilter mDrawFilter;
private ValueAnimator mProgressAnimator;
private int mInsideCurValue;
private int mExtCurValue;
public DoubleArcProgressBar(Context context) {
this(context, null);
}
public DoubleArcProgressBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DoubleArcProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initConfig(context, attrs);
initUtil();
}
/**
* 初始化布局配置
*/
private void initConfig(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DoubleArcProgressBar);
mStartAngle = a.getFloat(R.styleable.DoubleArcProgressBar_drpb_start_angle, 135);
mAngle = a.getFloat(R.styleable.DoubleArcProgressBar_drpb_angle, 270);
mInsideArcColor = a.getColor(R.styleable.DoubleArcProgressBar_drpb_inside_color, Color.GRAY);
mInsideProgressArcColor = a.getColor(R.styleable.DoubleArcProgressBar_drpb_inside_progress_color, Color.GREEN);
mInsideArcWidth = a.getDimensionPixelOffset(R.styleable.DoubleArcProgressBar_drpb_inside_width, dp2px(4));
mInsideMax = a.getInteger(R.styleable.DoubleArcProgressBar_drpb_inside_max, 100);
mInsideValue = a.getColor(R.styleable.DoubleArcProgressBar_drpb_inside_value, 10);
mInsideRadius = a.getDimensionPixelOffset(R.styleable.DoubleArcProgressBar_drpb_inside_radius, dp2px(35));
mExtArcColor = a.getColor(R.styleable.DoubleArcProgressBar_drpb_ext_color, Color.GRAY);
mExtProgressArcColor = a.getColor(R.styleable.DoubleArcProgressBar_drpb_ext_progress_color, Color.GREEN);
mExtArcWidth = a.getDimensionPixelOffset(R.styleable.DoubleArcProgressBar_drpb_ext_width, dp2px(4));
mExtMax = a.getInteger(R.styleable.DoubleArcProgressBar_drpb_ext_max, 100);
mExtValue = a.getColor(R.styleable.DoubleArcProgressBar_drpb_ext_value, 20);
mExtRadius = a.getDimensionPixelOffset(R.styleable.DoubleArcProgressBar_drpb_ext_radius, dp2px(43));
mText1Color = a.getColor(R.styleable.DoubleArcProgressBar_drpb_text1_color, Color.WHITE);
mText1Size = a.getDimensionPixelSize(R.styleable.DoubleArcProgressBar_drpb_text1_size, sp2px(12));
mText1 = a.getString(R.styleable.DoubleArcProgressBar_drpb_text1);
mText2Color = a.getColor(R.styleable.DoubleArcProgressBar_drpb_text2_color, Color.WHITE);
mText2Size = a.getDimensionPixelSize(R.styleable.DoubleArcProgressBar_drpb_text2_size, sp2px(12));
mText2 = a.getString(R.styleable.DoubleArcProgressBar_drpb_text2);
mText3Color = a.getColor(R.styleable.DoubleArcProgressBar_drpb_text3_color, Color.WHITE);
mText3Size = a.getDimensionPixelSize(R.styleable.DoubleArcProgressBar_drpb_text3_size, sp2px(12));
mText3 = a.getString(R.styleable.DoubleArcProgressBar_drpb_text3);
mText4Color = a.getColor(R.styleable.DoubleArcProgressBar_drpb_text4_color, Color.WHITE);
mText4Size = a.getDimensionPixelSize(R.styleable.DoubleArcProgressBar_drpb_text4_size, sp2px(12));
mText4 = a.getString(R.styleable.DoubleArcProgressBar_drpb_text4);
a.recycle();
}
private void initUtil() {
mInsideArcPaint = new Paint();
mInsideArcPaint.setAntiAlias(true);
mInsideArcPaint.setStyle(Paint.Style.STROKE);
mInsideArcPaint.setStrokeWidth(mInsideArcWidth);
mInsideArcPaint.setColor(mInsideArcColor);
mInsideArcPaint.setStrokeCap(Paint.Cap.ROUND);
mExtArcPaint = new Paint();
mExtArcPaint.setAntiAlias(true);
mExtArcPaint.setStyle(Paint.Style.STROKE);
mExtArcPaint.setStrokeWidth(mExtArcWidth);
mExtArcPaint.setColor(mExtArcColor);
mExtArcPaint.setStrokeCap(Paint.Cap.ROUND);
mText1Paint = new Paint();
mText1Paint.setAntiAlias(true);
mText1Paint.setTextSize(mText1Size);
mText1Paint.setColor(mText1Color);
mText1Paint.setTextAlign(Paint.Align.CENTER);
mText2Paint = new Paint();
mText2Paint.setAntiAlias(true);
mText2Paint.setTextSize(mText2Size);
mText2Paint.setColor(mText2Color);
mText2Paint.setTextAlign(Paint.Align.CENTER);
mText3Paint = new Paint();
mText3Paint.setAntiAlias(true);
mText3Paint.setTextSize(mText3Size);
mText3Paint.setColor(mText3Color);
mText3Paint.setTextAlign(Paint.Align.CENTER);
mText4Paint = new Paint();
mText4Paint.setAntiAlias(true);
mText4Paint.setTextSize(mText4Size);
mText4Paint.setColor(mText4Color);
mText4Paint.setTextAlign(Paint.Align.CENTER);
mRectText = new Rect();
mDrawFilter = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = getPaddingLeft() + getPaddingRight();
int height = getPaddingTop() + getPaddingBottom();
width += mExtRadius * 2 + mExtArcWidth;
height += mExtRadius * 2 + getFontHeight(mText4Paint, mText4Size) / 2 + mExtArcWidth;
setMeasuredDimension(width, height);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.setDrawFilter(mDrawFilter);
drawInsideArc(canvas);
drawExtArc(canvas);
drawText(canvas);
}
/**
* 绘制内部弧形
*/
private void drawInsideArc(Canvas canvas) {
if (mInsideRect == null) {
mInsideRect = new RectF();
mInsideRect.left = getCenterX() - mInsideRadius - mInsideArcWidth / 2;
mInsideRect.top = getCenterY() - mInsideRadius - mInsideArcWidth / 2;
mInsideRect.right = getCenterX() + mInsideRadius + mInsideArcWidth / 2;
mInsideRect.bottom = getCenterY() + mInsideRadius + mInsideArcWidth / 2;
}
mInsideArcPaint.setColor(mInsideArcColor);
canvas.drawArc(mInsideRect, mStartAngle, mAngle, false, mInsideArcPaint);
float angle = (mInsideCurValue * 1.0f / mInsideMax) * mAngle;
if (angle <= 0) {
return;
}
mInsideArcPaint.setColor(mInsideProgressArcColor);
canvas.drawArc(mInsideRect, mStartAngle, angle, false, mInsideArcPaint);
}
/**
* 绘制外部弧形
*/
private void drawExtArc(Canvas canvas) {
if (mExtRect == null) {
mExtRect = new RectF();
mExtRect.left = getCenterX() - mExtRadius - mExtArcWidth / 2;
mExtRect.top = getCenterY() - mExtRadius - mExtArcWidth / 2;
mExtRect.right = getCenterX() + mExtRadius + mExtArcWidth / 2;
mExtRect.bottom = getCenterY() + mExtRadius + mExtArcWidth / 2;
}
mExtArcPaint.setColor(mExtArcColor);
canvas.drawArc(mExtRect, mStartAngle, mAngle, false, mExtArcPaint);
float angle = (mExtCurValue * 1.0f / mExtMax) * mAngle;
if (angle <= 0) {
return;
}
mExtArcPaint.setColor(mExtProgressArcColor);
canvas.drawArc(mExtRect, mStartAngle, angle, false, mExtArcPaint);
}
/**
* 绘制文字
*
* @param canvas
*/
private void drawText(Canvas canvas) {
int x = 0;
int y = 0;
boolean text1IsNotEmp = mText1 != null && !mText1.isEmpty();
boolean text2IsNotEmp = mText2 != null && !mText2.isEmpty();
boolean text3IsNotEmp = mText3 != null && !mText3.isEmpty();
boolean text4IsNotEmp = mText4 != null && !mText4.isEmpty();
if (text1IsNotEmp) {
x = getCenterX();
y = getCenterY() - getFontHeight(mText1Paint, mText1Size);
if (text2IsNotEmp) {
y = y + getFontHeight(mText2Paint, mText2Size) / 3 + dp2px(2);
}
canvas.drawText(mText1, x, y, mText1Paint);
}
if (text2IsNotEmp) {
x = getCenterX();
y = getCenterY() + getFontHeight(mText2Paint, mText2Size) / 3;
canvas.drawText(mText2, x, y, mText2Paint);
}
if (text3IsNotEmp) {
x = getCenterX();
y = getCenterY() + mExtRadius - getFontHeight(mText3Paint, mText3Size) + dp2px(2);
canvas.drawText(mText3, x, y, mText3Paint);
}
if (text4IsNotEmp) {
x = getCenterX();
y = getCenterY() + mExtRadius;
canvas.drawText(mText4, x, y, mText4Paint);
}
}
/**
* 获取圆心x坐标
*
* @return x
*/
private int getCenterX() {
return getPaddingLeft() + mExtRadius + mExtArcWidth / 2;
}
/**
* 获取圆心u坐标
*
* @return y
*/
private int getCenterY() {
return getPaddingTop() + mExtRadius + mExtArcWidth / 2;
}
private int getFontHeight(Paint paint, int textSize) {
paint.setTextSize(textSize);
paint.getTextBounds("j", 0, 1, mRectText);
return mRectText.height();
}
private int getTextWidth(Paint paint, int textSize, String text) {
paint.setTextSize(textSize);
paint.getTextBounds(text, 0, text.length(), mRectText);
return mRectText.width();
}
public void setValue(int insideValue, int extValue) {
this.mInsideValue = insideValue;
this.mText1 = insideValue + "%";
this.mExtValue = extValue;
this.mText3 = extValue + "%";
startAnimation();
}
/**
* 为进度设置动画
*/
public void startAnimation() {
mProgressAnimator = ValueAnimator.ofFloat(0, mAngle);
mProgressAnimator.setDuration(ANIMATOR_DURATION);
mProgressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float angle = (float) animation.getAnimatedValue();
mInsideCurValue = (int) ((angle / mAngle) * mInsideValue);
mExtCurValue = (int) ((angle / mAngle) * mExtValue);
invalidate();
}
});
mProgressAnimator.start();
}
private int dp2px(int dp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
Resources.getSystem().getDisplayMetrics());
}
private int sp2px(int sp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp,
Resources.getSystem().getDisplayMetrics());
}
}
<declare-styleable name="DoubleArcProgressBar">
<attr name="drpb_start_angle" format="float" />
<attr name="drpb_angle" format="float" />
<attr name="drpb_inside_color" format="color"/>
<attr name="drpb_inside_progress_color" format="color"/>
<attr name="drpb_inside_width" format="dimension"/>
<attr name="drpb_inside_value" format="integer"/>
<attr name="drpb_inside_max" format="integer"/>
<attr name="drpb_inside_radius" format="dimension"/>
<attr name="drpb_ext_color" format="color"/>
<attr name="drpb_ext_progress_color" format="color"/>
<attr name="drpb_ext_width" format="dimension"/>
<attr name="drpb_ext_value" format="integer"/>
<attr name="drpb_ext_max" format="integer"/>
<attr name="drpb_ext_radius" format="dimension"/>
<attr name="drpb_text1_color" format="color" />
<attr name="drpb_text1_size" format="dimension" />
<attr name="drpb_text1" format="string"/>
<attr name="drpb_text2_color" format="color" />
<attr name="drpb_text2_size" format="dimension" />
<attr name="drpb_text2" format="string"/>
<attr name="drpb_text3_color" format="color" />
<attr name="drpb_text3_size" format="dimension" />
<attr name="drpb_text3" format="string"/>
<attr name="drpb_text4_color" format="color" />
<attr name="drpb_text4_size" format="dimension" />
<attr name="drpb_text4" format="string"/>
</declare-styleable>