自定義控制元件,動畫效果的進度圓環RingProgressBar
阿新 • • 發佈:2019-01-03
自定義動畫效果的進度圓環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>
刻度圖片資源
這個圖片大小是固定的,雖然程式裡做了適配,但是控制元件太大或太小多少會有點失真,所以儘量控制在圖片大小的尺寸比較好,當然看著舒服就好。
圖片在下面
圖片在上面