這次在網上直接找了別人現成的輪子來用
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.graphics.Shader;
import android.graphics.SweepGradient;
import android.graphics.Typeface;
import android.support.annotation.ColorInt;
import android.support.annotation.ColorRes;
import android.support.annotation.Nullable;
import android.text.TextPaint;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.View;
public class CircleProgressView extends View {
private Context context;
/**
* 畫筆
*/
private Paint mPaint;
/**
* 文本畫筆
*/
private TextPaint mTextPaint;
/**
* 筆畫描邊的寬度
*/
private float mStrokeWidth;
/**
* 開始角度(默認從12點鐘方向開始)
*/
private int mStartAngle = 270;
/**
* 掃描角度(一個圓)
*/
private int mSweepAngle = 360;
/**
* 圓心座標x
*/
private float mCircleCenterX;
/**
* 圓心座標y
*/
private float mCircleCenterY;
/**
* 圓正常顏色
*/
private int mNormalColor = 0xFFC8C8C8;
/**
* 進度顏色
*/
private int mProgressColor = 0xFF4FEAAC;
/**
* 是否使用着色器
*/
private boolean isShader = true;
/**
* 着色器
*/
private Shader mShader;
/**
* 着色器顏色
*/
private int[] mShaderColors = new int[]{0xFF4FEAAC, 0xFFA8DD51, 0xFFE8D30F, 0xFFA8DD51, 0xFF4FEAAC};
/**
* 半徑
*/
private float mRadius;
/**
* 內圓與外圓的間距
*/
private float mCirclePadding;
/**
* 刻度間隔的角度大小
*/
private float mTickSplitAngle = 5;
/**
* 刻度的角度大小
*/
private float mBlockAngle = 1;
/**
* 總刻度數
*/
private int mTotalTickCount;
/**
* 最大進度
*/
private int mMax = Integer.MAX_VALUE;
/**
* 當前進度
*/
private int mProgress = 0;
/**
* 動畫持續的時間
*/
private int mDuration = 500;
/**
* 標籤內容
*/
private String mLabelText;
/**
* 字體大小
*/
private float mLabelTextSize;
/**
* 字體顏色
*/
private int mLabelTextColor = 0xFF333333;
/**
* 進度百分比
*/
private float mProgressPercent;
private String mTextProgressPercent;
/**
* 是否顯示標籤文字
*/
private boolean isShowLabel = true;
/**
* 是否默認顯示百分比爲標籤文字
*/
private boolean isShowPercentText = true;
/**
* 是否顯示外邊框刻度
*/
private boolean isShowTick = true;
/**
* 是否旋轉
*/
private boolean isTurn = false;
private OnChangeListener mOnChangeListener;
public CircleProgressView(Context context) {
this(context, null);
}
public CircleProgressView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleProgressView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
/**
* 初始化
*
* @param context
* @param attrs
*/
private void init(Context context, AttributeSet attrs) {
this.context = context;
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleProgressView);
DisplayMetrics displayMetrics = getDisplayMetrics();
mStrokeWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 6, displayMetrics);
mLabelTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, displayMetrics);
mCirclePadding = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, displayMetrics);
int size = a.getIndexCount();
for (int i = 0; i < size; i++) {
int attr = a.getIndex(i);
if (attr == R.styleable.CircleProgressView_cpvStrokeWidth) {
mStrokeWidth = a.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 6, displayMetrics));
} else if (attr == R.styleable.CircleProgressView_cpvNormalColor) {
mNormalColor = a.getColor(attr, 0xFFC8C8C8);
} else if (attr == R.styleable.CircleProgressView_cpvProgressColor) {
mProgressColor = a.getColor(attr, 0xFF4FEAAC);
isShader = false;
} else if (attr == R.styleable.CircleProgressView_cpvStartAngle) {
mStartAngle = a.getInt(attr, 270);
} else if (attr == R.styleable.CircleProgressView_cpvSweepAngle) {
mSweepAngle = a.getInt(attr, 360);
} else if (attr == R.styleable.CircleProgressView_cpvMax) {
mMax = a.getInt(attr, 100);
} else if (attr == R.styleable.CircleProgressView_cpvProgress) {
mProgress = a.getInt(attr, 0);
} else if (attr == R.styleable.CircleProgressView_cpvDuration) {
mDuration = a.getInt(attr, 500);
} else if (attr == R.styleable.CircleProgressView_cpvLabelText) {
mLabelText = a.getString(attr);
} else if (attr == R.styleable.CircleProgressView_cpvLabelTextSize) {
mLabelTextSize = a.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 30, displayMetrics));
} else if (attr == R.styleable.CircleProgressView_cpvLabelTextColor) {
mLabelTextColor = a.getColor(attr, 0xFF333333);
} else if (attr == R.styleable.CircleProgressView_cpvShowLabel) {
isShowLabel = a.getBoolean(attr, true);
} else if (attr == R.styleable.CircleProgressView_cpvShowTick) {
isShowTick = a.getBoolean(attr, true);
} else if (attr == R.styleable.CircleProgressView_cpvCirclePadding) {
mCirclePadding = a.getDimension(attr, TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, displayMetrics));
} else if (attr == R.styleable.CircleProgressView_cpvTickSplitAngle) {
mTickSplitAngle = a.getInt(attr, 5);
} else if (attr == R.styleable.CircleProgressView_cpvBlockAngle) {
mBlockAngle = a.getInt(attr, 1);
} else if (attr == R.styleable.CircleProgressView_cpvTurn) {
isTurn = a.getBoolean(attr, false);
}
}
isShowPercentText = TextUtils.isEmpty(mLabelText);
a.recycle();
mProgressPercent = (int) (mProgress * 100.0f / mMax);
mPaint = new Paint();
mTextPaint = new TextPaint();
mTotalTickCount = (int) (mSweepAngle / (mTickSplitAngle + mBlockAngle));
}
private DisplayMetrics getDisplayMetrics() {
return getResources().getDisplayMetrics();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int defaultValue = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 200, getDisplayMetrics());
int width = measureHandler(widthMeasureSpec, defaultValue);
int height = measureHandler(heightMeasureSpec, defaultValue);
//圓心座標
mCircleCenterX = (width + getPaddingLeft() - getPaddingRight()) / 2.0f;
mCircleCenterY = (height + getPaddingTop() - getPaddingBottom()) / 2.0f;
//計算間距
int padding = Math.max(getPaddingLeft() + getPaddingRight(), getPaddingTop() + getPaddingBottom());
//半徑=視圖寬度-橫向或縱向內間距值 - 畫筆寬度
mRadius = (width - padding - mStrokeWidth) / 2.0f - mCirclePadding;
//默認着色器
mShader = new SweepGradient(mCircleCenterX, mCircleCenterX, mShaderColors, null);
setMeasuredDimension(width, height);
}
/**
* 測量
*
* @param measureSpec
* @param defaultSize
* @return
*/
private int measureHandler(int measureSpec, int defaultSize) {
int result = defaultSize;
int measureMode = MeasureSpec.getMode(measureSpec);
int measureSize = MeasureSpec.getSize(measureSpec);
if (measureMode == MeasureSpec.EXACTLY) {
result = measureSize;
} else if (measureMode == MeasureSpec.AT_MOST) {
result = Math.min(defaultSize, measureSize);
}
return result;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
drawArc(canvas);
drawText(canvas);
}
/**
* 繪製弧形(默認爲一個圓)
*
* @param canvas
*/
private void drawArc(Canvas canvas) {
mPaint.reset();
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(mStrokeWidth);
if (isShowTick) {//是否顯示外邊框刻度
float tickDiameter = mRadius * 2;
float tickStartX = mCircleCenterX - mRadius;
float tickStartY = mCircleCenterY - mRadius;
RectF rectF = new RectF(tickStartX, tickStartY, tickStartX + tickDiameter, tickStartY + tickDiameter);
final int currentBlockIndex = (int) (mProgressPercent / 100f * mTotalTickCount);
if (isTurn) {
for (int i = 0; i < mTotalTickCount; i++) {
//底層未選中刻度
mPaint.setShader(null);
mPaint.setColor(Color.parseColor("#FFF8F8F8"));
//繪製外邊框刻度
canvas.drawArc(rectF, i * (mBlockAngle + mTickSplitAngle) + mStartAngle, mBlockAngle, false, mPaint);
}
for (int i = currentBlockIndex; i < currentBlockIndex + currentBlockIndex; i++) {
//已選中的刻度
if (isShader && mShader != null) {
mPaint.setShader(mShader);
} else {
mPaint.setColor(mProgressColor);
}
//繪製外邊框刻度
canvas.drawArc(rectF, i * (mBlockAngle + mTickSplitAngle) + mStartAngle, mBlockAngle, false, mPaint);
}
} else {
for (int i = 0; i < mTotalTickCount; i++) {
if (i < currentBlockIndex) {
//已選中的刻度
if (isShader && mShader != null) {
mPaint.setShader(mShader);
} else {
mPaint.setColor(mProgressColor);
}
} else {
//未選中的刻度
mPaint.setShader(null);
mPaint.setColor(Color.parseColor("#FFF8F8F8"));
}
//繪製外邊框刻度
canvas.drawArc(rectF, i * (mBlockAngle + mTickSplitAngle) + mStartAngle, mBlockAngle, false, mPaint);
}
}
}
mPaint.setShader(null);
mPaint.setStrokeCap(Paint.Cap.SQUARE);
mPaint.setColor(Color.parseColor("#FFF8F8F8"));
//進度圓半徑
float circleRadius = isShowTick ? mRadius - mCirclePadding - mStrokeWidth : mRadius;
float diameter = circleRadius * 2;
float startX = mCircleCenterX - circleRadius;
float startY = mCircleCenterY - circleRadius;
RectF rectF1 = new RectF(startX, startY, startX + diameter, startY + diameter);
//繪製底層弧形
canvas.drawArc(rectF1, mStartAngle, mSweepAngle, false, mPaint);
//着色器不爲空則設置着色器,反之用純色
if (isShader && mShader != null) {
mPaint.setShader(mShader);
} else {
mPaint.setColor(mProgressColor);
}
if (isTurn) {
//繪製當前進度弧形
canvas.drawArc(rectF1, mStartAngle + mSweepAngle * getRatio(), mSweepAngle * getRatio(), false, mPaint);
} else {
//繪製當前進度弧形
canvas.drawArc(rectF1, mStartAngle, mSweepAngle * getRatio(), false, mPaint);
}
}
/**
* 繪製中間的文本
*
* @param canvas
*/
private void drawText(Canvas canvas) {
if (!isShowLabel) {
return;
}
mTextPaint.reset();
mTextPaint.setAntiAlias(true);
mTextPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mTextPaint.setTypeface(Typeface.createFromAsset(context.getAssets(), "din_alternate.ttf"));
mTextPaint.setTextSize(mLabelTextSize);
mTextPaint.setColor(mLabelTextColor);
mTextPaint.setTextAlign(Paint.Align.CENTER);
Paint.FontMetrics fontMetrics = mTextPaint.getFontMetrics();
// 計算文字高度
float fontHeight = fontMetrics.bottom - fontMetrics.top;
// 計算文字baseline
float textBaseY = getHeight() - (getHeight() - fontHeight) / 2 - fontMetrics.bottom;
if (isShowPercentText) {//是否顯示百分比
canvas.drawText(mTextProgressPercent, getWidth() / 2, textBaseY, mTextPaint);
} else if (!TextUtils.isEmpty(mLabelText)) {//顯示自定義文本
canvas.drawText(mLabelText, getWidth() / 2, textBaseY, mTextPaint);
}
}
/**
* 顯示進度動畫效果(根據當前已有進度開始)
* @param progress
*/
public void showAppendAnimation(int progress){
showAnimation(mProgress,progress,mDuration);
}
/**
* 顯示進度動畫效果
* @param progress
*/
public void showAnimation(int progress){
showAnimation(progress,mDuration);
}
/**
* 顯示進度動畫效果
* @param progress
* @param duration 動畫時長
*/
public void showAnimation(int progress,int duration){
showAnimation(0,progress,duration);
}
/**
* 顯示進度動畫效果,從from到to變化
* @param from
* @param to
* @param duration 動畫時長
*/
public void showAnimation(int from,int to,int duration){
this.mDuration = duration;
this.mProgress = from;
ValueAnimator valueAnimator = ValueAnimator.ofInt(from,to);
valueAnimator.setDuration(duration);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
setProgress((int)animation.getAnimatedValue());
}
});
valueAnimator.start();
}
/**
* 進度比例
*
* @return
*/
private float getRatio() {
return mProgress * 1.0f / mMax;
}
/**
* 設置最大進度
*
* @param max
*/
public void setMax(int max) {
this.mMax = max;
invalidate();
}
/**
* 設置當前進度
*
* @param progress
*/
public void setProgress(int progress) {
this.mProgress = progress;
mProgressPercent = (float) (mProgress * 100.0f / mMax);
mTextProgressPercent = TransformUtils.getPercent(String.valueOf(mProgress), String.valueOf(mMax), 2);
invalidate();
if (mOnChangeListener != null) {
mOnChangeListener.onProgressChanged(mProgress, mMax);
}
}
/**
* 設置正常顏色
*
* @param color
*/
public void setNormalColor(@ColorInt int color) {
this.mNormalColor = color;
invalidate();
}
/**
* 設置着色器
*
* @param shader
*/
public void setShader(Shader shader) {
isShader = true;
this.mShader = shader;
invalidate();
}
/**
* 設置進度顏色(通過着色器實現漸變色)
*
* @param colors
*/
public void setProgressColor(@ColorInt int... colors) {
Shader shader = new SweepGradient(mCircleCenterX, mCircleCenterX, colors, null);
setShader(shader);
}
/**
* 設置進度顏色(純色)
*
* @param color
*/
public void setProgressColor(@ColorInt int color) {
isShader = false;
this.mProgressColor = color;
invalidate();
}
/**
* 設置進度顏色
*
* @param resId
*/
public void setProgressColorResource(@ColorRes int resId) {
int color = getResources().getColor(resId);
setProgressColor(color);
}
/**
* 設置是否顯示外環刻度
*
* @param isShowTick
*/
public void setShowTick(boolean isShowTick) {
this.isShowTick = isShowTick;
invalidate();
}
/**
* 設置是否旋轉
*
* @param isTurn
*/
public void setTurn(boolean isTurn) {
this.isTurn = isTurn;
invalidate();
}
public int getStartAngle() {
return mStartAngle;
}
public int getSweepAngle() {
return mSweepAngle;
}
public float getCircleCenterX() {
return mCircleCenterX;
}
public float getCircleCenterY() {
return mCircleCenterY;
}
public float getRadius() {
return mRadius;
}
public long getMax() {
return mMax;
}
public long getProgress() {
return mProgress;
}
public String getLabelText() {
return mLabelText;
}
/**
* 設置標籤文本
*
* @param labelText
*/
public void setLabelText(String labelText) {
this.mLabelText = labelText;
this.isShowPercentText = TextUtils.isEmpty(labelText);
invalidate();
}
/**
* 進度百分比
*
* @return
*/
public float getProgressPercent() {
return mProgressPercent;
}
/**
* 如果自定義設置過{@link #setLabelText(String)} 或通過xml設置過{@code app:labelText}則
* 返回{@link #mLabelText},反之默認返回百分比{@link #mProgressPercent}
*
* @return
*/
public String getText() {
if (isShowPercentText) {
return mTextProgressPercent;
}
return mLabelText;
}
public int getLabelTextColor() {
return mLabelTextColor;
}
public void setLabelTextColor(@ColorInt int labelTextColor) {
this.mLabelTextColor = labelTextColor;
invalidate();
}
public void setLabelTextColorResource(@ColorRes int resId) {
int color = getResources().getColor(resId);
setLabelTextColor(color);
}
public void setLabelTextSize(float textSize) {
setLabelTextSize(TypedValue.COMPLEX_UNIT_SP, textSize);
}
public void setLabelTextSize(int unit, float textSize) {
float size = TypedValue.applyDimension(unit, textSize, getDisplayMetrics());
if (mLabelTextSize != size) {
this.mLabelTextSize = size;
invalidate();
}
}
/**
* 設置進度改變監聽
*
* @param onChangeListener
*/
public void setOnChangeListener(OnChangeListener onChangeListener) {
this.mOnChangeListener = onChangeListener;
}
public interface OnChangeListener {
void onProgressChanged(float progress, float max);
}
}