1. 程式人生 > >自定義控制元件,動畫效果的進度圓環RingProgressBar

自定義控制元件,動畫效果的進度圓環RingProgressBar

自定義動畫效果的進度圓環RingProgressBar

專案中有一個進度圓環,實現一個比例的顯示,原生的ProgressBar就算自定義樣式也不是很美觀,於是就自定義了一個,繼承於View類,效果如下:

動畫效果圖

程式碼

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import
android.graphics.Matrix; import android.graphics.Paint; import android.graphics.RectF; import android.graphics.Shader; import android.graphics.SweepGradient; import android.os.Handler; import android.util.AttributeSet; import android.util.Log; import android.view.View; /** * 環形進度條 * Created by Wood on 2016/7/21. */
public class RingProgressBar extends View { private static final String LOG_TAG = "RingProgressBar"; /** * 總值 */ private double max = 100; /** * 已使用 */ private double progress = 0; /** * 目標比例 */ private double aimAngle; /** * 進度條畫筆 */ private
Paint mPaint; private int strokeWidth = 12; private int wh; private int center; private int radius; private RectF oval; private Handler handler = new Handler(); private int angle = -1; /** * 著色器,這裡使用了一個掃描渲染器(SweepGradient)實現漸變色 */ private Shader shader; /** * 刻度背景圖 */ private Bitmap bitmapBackground; /** * 開始的顏色 */ private int startColor = Color.parseColor("#303F9F");//開始顏色 /** * 中間的顏色 */ private int centerColor = Color.parseColor("#FF4081");//中間顏色 /** * 結束的顏色 */ private int endColor = Color.parseColor("#303F9F");//開始顏色 /** * 進度條顏色陣列 */ private int[] colors = new int[]{ startColor, centerColor, endColor }; /** * 刻度縮放比率 */ private float ratio = 1; public RingProgressBar(Context context) { this(context, null); } public RingProgressBar(Context context, AttributeSet attrs) { super(context, attrs); TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RingProgressBar); startColor = a.getColor(R.styleable.RingProgressBar_startColor, startColor); centerColor = a.getColor(R.styleable.RingProgressBar_centerColor, centerColor); endColor = a.getColor(R.styleable.RingProgressBar_endColor, endColor); max = (double) a.getFloat(R.styleable.RingProgressBar_max, (float) max); progress = (double) a.getFloat(R.styleable.RingProgressBar_progress, (float) progress); a.recycle(); colors = new int[]{startColor, centerColor, endColor}; init(); setValue(max, progress); } private void init() { bitmapBackground = BitmapFactory.decodeResource(getResources(), R.mipmap.dial); strokeWidth = dip2px(12); mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(strokeWidth); mPaint.setStrokeCap(Paint.Cap.ROUND); aimAngle = -1; } /** * 畫進度環,這裡控制圓環的動畫速度,可以調整一個合適的速度 */ Runnable runnable = new Runnable() { @Override public void run() { angle += 6; if (angle <= aimAngle) { postInvalidate(); handler.postDelayed(runnable, 3); } } }; @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (progress > 0) { canvas.drawArc(oval, -90, angle, false, mPaint); } //根據空間大小縮放刻度背景圖片 Matrix matrix = new Matrix(); matrix.postScale(ratio, ratio); Bitmap bmp = Bitmap.createBitmap(bitmapBackground, 0, 0, bitmapBackground.getWidth(), bitmapBackground.getHeight(), matrix, true); canvas.drawBitmap(bmp, 0, 0, mPaint); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); Log.e(LOG_TAG, "width:" + width + "...height:" + height); Log.e(LOG_TAG, "bitmapBackground.width:" + bitmapBackground.getWidth() + "...bitmapBackground.height:" + bitmapBackground.getHeight()); wh = Math.min(width, height); if (bitmapBackground.getWidth() != 0 && wh != 0) { ratio = (float) wh / (float) bitmapBackground.getWidth(); } center = wh / 2; radius = center - strokeWidth / 2; oval = new RectF(center - radius, center - radius, center + radius, center + radius); shader = new SweepGradient(center, center, colors, null); Matrix m = new Matrix(); m.setRotate(-90, center, center); shader.setLocalMatrix(m); mPaint.setShader(shader); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } /** * 釋放bitmap資源 */ public void clearBitmap() { if (bitmapBackground != null && !bitmapBackground.isRecycled()) { bitmapBackground.recycle(); } } /** * 設定目標比率 * * @param max * @param progress */ public void setValue(double max, double progress) { this.max = max; this.progress = progress; if (max != 0f) { aimAngle = progress / max * 360; } angle = -1; handler.postDelayed(runnable, 400);//這裡延時一下執行,有時候頁面載入延時可能看不到動畫 } /** * 獲取最大進度,預設100 * * @return */ public double getMax() { return max; } /** * 設定最大進度 * * @param max */ public void setMax(double max) { if (max > 0) { this.max = max; } } /** * 獲取當前進度,預設0 * * @return */ public double getProgress() { return progress; } /** * 設定當前進度 * * @param progress */ public void setProgress(double progress) { if (progress >= 0) { this.progress = progress; } if (max >= 0 && max >= progress) { setValue(max, progress); } } /** * dp轉px * * @param dip * @return */ private int dip2px(float dip) { float density = getContext().getResources().getDisplayMetrics().density; int px = (int) (dip * density + 0.5f); return px; } }

自定義屬性

設定起始中間和結束的顏色,使用SweepGradient渲染器,實現扇形的顏色漸變,如果想自己定製更多顏色,可以改變程式碼裡的陣列,在這裡只提供三種顏色設定。還提供最大值和進度值
的設定。也可通過程式裡的set方法設定顏色和進度資訊。

<!-- RingProgressBar -->
    <declare-styleable name="RingProgressBar">
        <attr name="startColor" format="color" />
        <attr name="centerColor" format="color" />
        <attr name="endColor" format="color" />
        <attr name="max" format="float" />
        <attr name="progress" format="float" />
    </declare-styleable>

刻度圖片資源

這個圖片大小是固定的,雖然程式裡做了適配,但是控制元件太大或太小多少會有點失真,所以儘量控制在圖片大小的尺寸比較好,當然看著舒服就好。

圖片在下面

刻度圖片資源,有點透明,設個背景色就看見了

圖片在上面