自定義progress之三種風格的圖片載入進度樣式
阿新 • • 發佈:2018-12-21
效果圖: 自定義CircleProgressView:
public class CircleProgressView extends ProgressBar {
private int mReachBarSize = DisplayUtil.dip2px(getContext(), 2); // 未完成進度條大小
private int mNormalBarSize = DisplayUtil.dip2px(getContext(), 2); // 未完成進度條大小
private int mReachBarColor = Color.parseColor("#108ee9" ); // 已完成進度顏色
private int mNormalBarColor = Color.parseColor("#FFD3D6DA"); // 未完成進度顏色
private int mTextSize = DisplayUtil.sp2px(getContext(), 14); // 進度值字型大小
private int mTextColor = Color.parseColor("#108ee9"); // 進度的值字型顏色
private float mTextSkewX; // 進度值字型傾斜角度
private String mTextSuffix = "%"; // 進度值字首
private String mTextPrefix = ""; // 進度值字尾
private boolean mTextVisible = true; // 是否顯示進度值
private boolean mReachCapRound; // 畫筆是否使用圓角邊界,normalStyle下生效
private int mRadius = DisplayUtil.dip2px(getContext(), 20); // 半徑
private int mStartArc; // 起始角度
private int mInnerBackgroundColor; // 內部背景填充顏色
private int mProgressStyle = ProgressStyle.NORMAL; // 進度風格
private int mInnerPadding = DisplayUtil.dip2px(getContext(), 1); // 內部圓與外部圓間距
private int mOuterColor; // 外部圓環顏色
private boolean needDrawInnerBackground; // 是否需要繪製內部背景
private RectF rectF; // 外部圓環繪製區域
private RectF rectInner; // 內部圓環繪製區域
private int mOuterSize = DisplayUtil.dip2px(getContext(), 1); // 外層圓環寬度
private Paint mTextPaint; // 繪製進度值字型畫筆
private Paint mNormalPaint; // 繪製未完成進度畫筆
private Paint mReachPaint; // 繪製已完成進度畫筆
private Paint mInnerBackgroundPaint; // 內部背景畫筆
private Paint mOutPaint; // 外部圓環畫筆
private int mRealWidth;
private int mRealHeight;
@IntDef({ProgressStyle.NORMAL, ProgressStyle.FILL_IN, ProgressStyle.FILL_IN_ARC})
@Retention(RetentionPolicy.SOURCE)
public @interface ProgressStyle {
int NORMAL = 0;
int FILL_IN = 1;
int FILL_IN_ARC = 2;
}
public CircleProgressView(Context context) {
this(context, null);
}
public CircleProgressView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleProgressView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
obtainAttributes(attrs);
initPaint();
}
private void initPaint() {
mTextPaint = new Paint();
mTextPaint.setColor(mTextColor);
mTextPaint.setStyle(Paint.Style.FILL);
mTextPaint.setTextSize(mTextSize);
mTextPaint.setTextSkewX(mTextSkewX);
mTextPaint.setAntiAlias(true);
mNormalPaint = new Paint();
mNormalPaint.setColor(mNormalBarColor);
mNormalPaint.setStyle(mProgressStyle == ProgressStyle.FILL_IN_ARC ? Paint.Style.FILL : Paint.Style.STROKE);
mNormalPaint.setAntiAlias(true);
mNormalPaint.setStrokeWidth(mNormalBarSize);
mReachPaint = new Paint();
mReachPaint.setColor(mReachBarColor);
mReachPaint.setStyle(mProgressStyle == ProgressStyle.FILL_IN_ARC ? Paint.Style.FILL : Paint.Style.STROKE);
mReachPaint.setAntiAlias(true);
mReachPaint.setStrokeCap(mReachCapRound ? Paint.Cap.ROUND : Paint.Cap.BUTT);
mReachPaint.setStrokeWidth(mReachBarSize);
if (needDrawInnerBackground) {
mInnerBackgroundPaint = new Paint();
mInnerBackgroundPaint.setStyle(Paint.Style.FILL);
mInnerBackgroundPaint.setAntiAlias(true);
mInnerBackgroundPaint.setColor(mInnerBackgroundColor);
}
if (mProgressStyle == ProgressStyle.FILL_IN_ARC) {
mOutPaint = new Paint();
mOutPaint.setStyle(Paint.Style.STROKE);
mOutPaint.setColor(mOuterColor);
mOutPaint.setStrokeWidth(mOuterSize);
mOutPaint.setAntiAlias(true);
}
}
private void obtainAttributes(AttributeSet attrs) {
TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.CircleProgressView);
mProgressStyle = ta.getInt(R.styleable.CircleProgressView_cpv_progressStyle, ProgressStyle.NORMAL);
// 獲取三種風格通用的屬性
mNormalBarSize = (int) ta.getDimension(R.styleable.CircleProgressView_cpv_progressNormalSize, mNormalBarSize);
mNormalBarColor = ta.getColor(R.styleable.CircleProgressView_cpv_progressNormalColor, mNormalBarColor);
mReachBarSize = (int) ta.getDimension(R.styleable.CircleProgressView_cpv_progressReachSize, mReachBarSize);
mReachBarColor = ta.getColor(R.styleable.CircleProgressView_cpv_progressReachColor, mReachBarColor);
mTextSize = (int) ta.getDimension(R.styleable.CircleProgressView_cpv_progressTextSize, mTextSize);
mTextColor = ta.getColor(R.styleable.CircleProgressView_cpv_progressTextColor, mTextColor);
mTextSkewX = ta.getDimension(R.styleable.CircleProgressView_cpv_progressTextSkewX, 0);
if (ta.hasValue(R.styleable.CircleProgressView_cpv_progressTextSuffix)) {
mTextSuffix = ta.getString(R.styleable.CircleProgressView_cpv_progressTextSuffix);
}
if (ta.hasValue(R.styleable.CircleProgressView_cpv_progressTextPrefix)) {
mTextPrefix = ta.getString(R.styleable.CircleProgressView_cpv_progressTextPrefix);
}
mTextVisible = ta.getBoolean(R.styleable.CircleProgressView_cpv_progressTextVisible, mTextVisible);
mRadius = (int) ta.getDimension(R.styleable.CircleProgressView_cpv_radius, mRadius);
rectF = new RectF(-mRadius, -mRadius, mRadius, mRadius);
switch (mProgressStyle) {
case ProgressStyle.FILL_IN:
mReachBarSize = 0;
mNormalBarSize = 0;
mOuterSize = 0;
break;
case ProgressStyle.FILL_IN_ARC:
mStartArc = ta.getInt(R.styleable.CircleProgressView_cpv_progressStartArc, 0) + 270;
mInnerPadding = (int) ta.getDimension(R.styleable.CircleProgressView_cpv_innerPadding, mInnerPadding);
mOuterColor = ta.getColor(R.styleable.CircleProgressView_cpv_outerColor, mReachBarColor);
mOuterSize = (int) ta.getDimension(R.styleable.CircleProgressView_cpv_outerSize, mOuterSize);
mReachBarSize = 0;// 將畫筆大小重置為0
mNormalBarSize = 0;
if (!ta.hasValue(R.styleable.CircleProgressView_cpv_progressNormalColor)) {
mNormalBarColor = Color.TRANSPARENT;
}
int mInnerRadius = mRadius - mOuterSize / 2 - mInnerPadding;
rectInner = new RectF(-mInnerRadius, -mInnerRadius, mInnerRadius, mInnerRadius);
break;
case ProgressStyle.NORMAL:
mReachCapRound = ta.getBoolean(R.styleable.CircleProgressView_cpv_reachCapRound, true);
mStartArc = ta.getInt(R.styleable.CircleProgressView_cpv_progressStartArc, 0) + 270;
if (ta.hasValue(R.styleable.CircleProgressView_cpv_innerBackgroundColor)) {
mInnerBackgroundColor = ta.getColor(R.styleable.CircleProgressView_cpv_innerBackgroundColor, Color.argb(0, 0, 0, 0));
needDrawInnerBackground = true;
}
break;
}
ta.recycle();
}
@Override
protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int maxBarPaintWidth = Math.max(mReachBarSize, mNormalBarSize);
int maxPaintWidth = Math.max(maxBarPaintWidth, mOuterSize);
int height = 0;
int width = 0;
switch (mProgressStyle) {
case ProgressStyle.FILL_IN:
height = getPaddingTop() + getPaddingBottom() // 邊距
+ Math.abs(mRadius * 2); // 直徑
width = getPaddingLeft() + getPaddingRight() // 邊距
+ Math.abs(mRadius * 2); // 直徑
break;
case ProgressStyle.FILL_IN_ARC:
height = getPaddingTop() + getPaddingBottom() // 邊距
+ Math.abs(mRadius * 2) // 直徑
+ maxPaintWidth;// 邊框
width = getPaddingLeft() + getPaddingRight() // 邊距
+ Math.abs(mRadius * 2) // 直徑
+ maxPaintWidth;// 邊框
break;
case ProgressStyle.NORMAL:
height = getPaddingTop() + getPaddingBottom() // 邊距
+ Math.abs(mRadius * 2) // 直徑
+ maxBarPaintWidth;// 邊框
width = getPaddingLeft() + getPaddingRight() // 邊距
+ Math.abs(mRadius * 2) // 直徑
+ maxBarPaintWidth;// 邊框
break;
}
mRealWidth = resolveSize(width, widthMeasureSpec);
mRealHeight = resolveSize(height, heightMeasureSpec);
setMeasuredDimension(mRealWidth, mRealHeight);
}
@Override
protected synchronized void onDraw(Canvas canvas) {
switch (mProgressStyle) {
case ProgressStyle.NORMAL:
drawNormalCircle(canvas);
break;
case ProgressStyle.FILL_IN:
drawFillInCircle(canvas);
break;
case ProgressStyle.FILL_IN_ARC:
drawFillInArcCircle(canvas);
break;
}
}
/**
* 繪製PROGRESS_STYLE_FILL_IN_ARC圓形
*/
private void drawFillInArcCircle(Canvas canvas) {
canvas.save();
canvas.translate(mRealWidth / 2, mRealHeight / 2);
// 繪製外層圓環
canvas.drawArc(rectF, 0, 360, false, mOutPaint);
// 繪製內層進度實心圓弧
// 內層圓弧半徑
float reachArc = getProgress() * 1.0f / getMax() * 360;
canvas.drawArc(rectInner, mStartArc, reachArc, true, mReachPaint);
// 繪製未到達進度
if (reachArc != 360) {
canvas.drawArc(rectInner, reachArc + mStartArc, 360 - reachArc, true, mNormalPaint);
}
canvas.restore();
}
/**
* 繪製PROGRESS_STYLE_FILL_IN圓形
*/
private void drawFillInCircle(Canvas canvas) {
canvas.save();
canvas.translate(mRealWidth / 2, mRealHeight / 2);
float progressY = getProgress() * 1.0f / getMax() * (mRadius * 2);
float angle = (float) (Math.acos((mRadius - progressY) / mRadius) * 180 / Math.PI);
float startAngle = 90 + angle;
float sweepAngle = 360 - angle * 2;
// 繪製未到達區域
rectF = new RectF(-mRadius, -mRadius, mRadius, mRadius);
mNormalPaint.setStyle(Paint.Style.FILL);
canvas.drawArc(rectF, startAngle, sweepAngle, false, mNormalPaint);
// 翻轉180度繪製已到達區域
canvas.rotate(180);
mReachPaint.setStyle(Paint.Style.FILL);
canvas.drawArc(rectF, 270 - angle, angle * 2, false, mReachPaint);
// 文字顯示在最上層最後繪製
canvas.rotate(180);
// 繪製文字
if (mTextVisible) {
String text = mTextPrefix + getProgress() + mTextSuffix;
float textWidth = mTextPaint.measureText(text);
float textHeight = (mTextPaint.descent() + mTextPaint.ascent());
canvas.drawText(text, -textWidth / 2, -textHeight / 2, mTextPaint);
}
}
/**
* 繪製PROGRESS_STYLE_NORMAL圓形
*/
private void drawNormalCircle(Canvas canvas) {
canvas.save();
canvas.translate(mRealWidth / 2, mRealHeight / 2);
// 繪製內部圓形背景色
if (needDrawInnerBackground) {
canvas.drawCircle(0, 0, mRadius - Math.min(mReachBarSize, mNormalBarSize) / 2,
mInnerBackgroundPaint);
}
// 繪製文字
if (mTextVisible) {
String text = mTextPrefix + getProgress() + mTextSuffix;
float textWidth = mTextPaint.measureText(text);
float textHeight = (mTextPaint.descent() + mTextPaint.ascent());
canvas.drawText(text, -textWidth / 2, -textHeight / 2, mTextPaint);
}
// 計算進度值
float reachArc = getPro