1. 程式人生 > >自定義progress之三種風格的圖片載入進度樣式

自定義progress之三種風格的圖片載入進度樣式

效果圖: 自定義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