自定義圓形進度條(一)
阿新 • • 發佈:2018-12-31
由於專案需要,需要自定義一個圓形進度條,效果如下:
1 建立什麼檔案?
具體的程式碼我會放在github上,所以暫時忽略attr檔案和activity_main2檔案
2 CustomCircleProgressBar
package com.demo1.views;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.LinearInterpolator;
import com.demo1.R;
import static android.graphics.Paint.Style.STROKE;
public class CustomCircleProgressBar extends View {
private int outsideColor; //進度的顏色
private float circleRadius; //外圓半徑大小
private int insideColor; //背景顏色
private int progressTextColor; //圓環內文字顏色
private float progressTextSize; //圓環內文字大小
private float progressWidth; //圓環的寬度
private int maxProgress; //最大進度
private float progress; //當前進度
private Paint paint;
private String progressText; //圓環內文字
private Rect rect;
private ValueAnimator animator;
public CustomCircleProgressBar(Context context) {
this(context, null);
}
public CustomCircleProgressBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CustomCircleProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomCircleProgressBar, defStyleAttr, 0);
outsideColor = a.getColor(R.styleable.CustomCircleProgressBar_outside_color, ContextCompat.getColor(getContext(), R.color.colorPrimary));
circleRadius = a.getDimension(R.styleable.CustomCircleProgressBar_circle_radius, dp2px(getContext(), 60.0f));
insideColor = a.getColor(R.styleable.CustomCircleProgressBar_inside_color, ContextCompat.getColor(getContext(), R.color.inside_color));
progressTextColor = a.getColor(R.styleable.CustomCircleProgressBar_progress_text_color, ContextCompat.getColor(getContext(), R.color.colorPrimary));
progressTextSize = a.getDimension(R.styleable.CustomCircleProgressBar_progress_text_size, dp2px(getContext(), 14.0f));
progressWidth = a.getDimension(R.styleable.CustomCircleProgressBar_progress_width, dp2px(getContext(), 10.0f));
progress = a.getFloat(R.styleable.CustomCircleProgressBar_progress, 50.0f);
maxProgress = a.getInt(R.styleable.CustomCircleProgressBar_max_progress, 100);
a.recycle();
paint = new Paint();
}
/**
* dp轉px
*/
public static int dp2px(Context context, float dp) {
return (int) (dp * context.getResources().getDisplayMetrics().density + 0.5f);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int circlePoint = getMeasuredWidth() / 2;
//第一步:畫背景(即內層圓)
paint.setColor(insideColor); //設定圓的顏色
paint.setStyle(STROKE); //設定空心
paint.setStrokeWidth(progressWidth); //設定圓的寬度
paint.setAntiAlias(true); //消除鋸齒
canvas.drawCircle(circlePoint, circlePoint, circleRadius, paint); //畫出圓
//第二步:畫進度(圓弧)
paint.setColor(outsideColor); //設定進度的顏色
RectF oval = new RectF(circlePoint - circleRadius, circlePoint - circleRadius, circlePoint + circleRadius, circlePoint + circleRadius); //用於定義的圓弧的形狀和大小的界限
canvas.drawArc(oval, -90, 360 * (progress / maxProgress), false, paint); //根據進度畫圓弧
//第三步:畫圓環內百分比文字
rect = new Rect();
paint.setColor(progressTextColor);
paint.setTextSize(progressTextSize);
paint.setStrokeWidth(0);
progressText = getProgressText();
paint.getTextBounds(progressText, 0, progressText.length(), rect);
Paint.FontMetricsInt fontMetrics = paint.getFontMetricsInt();
int baseline = (getMeasuredHeight() - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top; //獲得文字的基準線
canvas.drawText(progressText, getMeasuredWidth() / 2 - rect.width() / 2, baseline, paint);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width;
int height;
int size = MeasureSpec.getSize(widthMeasureSpec);
int mode = MeasureSpec.getMode(widthMeasureSpec);
if (mode == MeasureSpec.EXACTLY) {
width = size;
} else {
width = (int) ((2 * circleRadius) + progressWidth);
}
size = MeasureSpec.getSize(heightMeasureSpec);
mode = MeasureSpec.getMode(heightMeasureSpec);
if (mode == MeasureSpec.EXACTLY) {
height = size;
} else {
height = (int) ((2 * circleRadius) + progressWidth);
}
setMeasuredDimension(width, height);
}
//中間的進度百分比
private String getProgressText() {
return (int) ((progress / maxProgress) * 100) + "%";
}
public synchronized int getMaxProgress() {
return maxProgress;
}
public synchronized void setMaxProgress(int maxProgress) {
if (maxProgress < 0) {
//此為傳遞非法引數異常
throw new IllegalArgumentException("maxProgress should not be less than 0");
}
this.maxProgress = maxProgress;
}
public synchronized float getProgress() {
return progress;
}
//加鎖保證執行緒安全,能線上程中使用
public synchronized void setProgress(int progress) {
if (progress < 0) {
throw new IllegalArgumentException("progress should not be less than 0");
}
if (progress > maxProgress) {
progress = maxProgress;
}
startAnim(progress);
}
/**
* 設定動畫
* @param progress 進度的整數 80,100,等值
*/
private void startAnim(float progress) {
animator = ObjectAnimator.ofFloat(0, progress);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
CustomCircleProgressBar.this.progress = (float) animation.getAnimatedValue();
postInvalidate();
}
});
animator.setStartDelay(500);
animator.setDuration(2000);
animator.setInterpolator(new LinearInterpolator());//勻速動畫
animator.start();
}
}
如果不研究原始碼也不想了解來龍去脈的話到這裡就可以結束了,這是原始碼地址
如果有時間研究原始碼歡迎瀏覽我的下一篇部落格:
自定義圓形進度條(二)