前言
刚到简书不久,看了好多五分钟学会系列。今天我也来分享个五分钟学会,也许能帮到大家。先上图:

没错,就是圆形刻度的进度条,刻度颜色是渐变的,下面的SeekBar是用来做对比的。接下来讲怎么实现。
刻度
如何画一个刻度呢?Canvas类提供了方法
public void drawArc(@NonNull RectF oval,float startAngle,float sweepAngle,boolean useCenter,
@NonNull Paintpaint)
startAngle:起始角度
sweepAngle:从起始到结束的角度。试一下效果:
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setColor(Color.GRAY);
........
canvas.drawArc(mRect, 0, 3, false, mPaint);
canvas.drawArc(mRect, 9, 3, false, mPaint);

渐变
一开始想到用环形渐变SweepGradient:Paint.setShader(SweepGradient)
,结果效果不理想,改用ArgbEvaluator:
mPaint.setColor((Integer) mArgbEvaluator.evaluate(i * (mBlockAngle + mTickSplitAngle)/(360), mGradientStartColor ,mGradientEndColor));
该方法的内部实现请看:
public Object evaluate(float fraction, Object startValue, Object endValue) {
int startInt = (Integer) startValue;
int startA = (startInt >> 24) & 0xff;
int startR = (startInt >> 16) & 0xff;
int startG = (startInt >> 8) & 0xff;
int startB = startInt & 0xff;
int endInt = (Integer) endValue;
int endA = (endInt >> 24) & 0xff;
int endR = (endInt >> 16) & 0xff;
int endG = (endInt >> 8) & 0xff;
int endB = endInt & 0xff;
return (int)((startA + (int)(fraction * (endA - startA))) << 24) |
(int)((startR + (int)(fraction * (endR - startR))) << 16) |
(int)((startG + (int)(fraction * (endG - startG))) << 8) |
(int)((startB + (int)(fraction * (endB - startB))));
}
总结
刻度和渐变都解决了,接下去就比较简单了,设定每个刻度的角度、间隔角度,计算出刻度数量 = 360 / (刻度角度 + 间隔角度),然后依次drawArc即可。
完整代码
package com.zhb.customview;
import android.animation.ArgbEvaluator;
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.SweepGradient;
import android.util.AttributeSet;
import android.view.View;
/**
* Created by zhb on 2017/2/26.
*/
public class CircleProgressBar extends View {
private Object lock = new Object();
/**默认刻度间隔角度*/
private final int TICK_SPLIT_DEFAULT_ANGLE = 3;
/**默认刻度角度*/
private final int TICK_BLOCK_DEFAULT_ANGLE = 3;
/**默认刻度长度*/
private final float NORMAL_TICK_DEFAULT_SIZE = 60;
/**默认当前刻度长度*/
private final float CURRENT_TICK_DEFAULT_SIZE = 85;
/**默认渐变起始颜色*/
private final int GRADIENT_START_DEFAULT_COLOR = Color.GREEN;
/**默认渐变结束颜色*/
private final int GRADIENT_END_DEFAULT_COLOR = Color.RED;
private final int TICK_NORMAL_DEFAULT_COLOR = Color.GRAY;
private Paint mPaint;
/**刻度数量*/
private int mTotalTickCount;
/**刻度间隔*/
private float mTickSplitAngle;
/**正常刻度的长度*/
private float mNormalTickSize;
/**当前刻度的长度*/
private float mCurrentTickSize;
/**渐变起始颜色*/
private int mGradientStartColor;
/**渐变结束颜色*/
private int mGradientEndColor;
/**刻度未选中颜色*/
private int mTickNormalColor;
/**当前进度*/
private int mCurrentProgressPercent;
/**直径*/
private int mCircleWidth;
/**刻度角度*/
private float mBlockAngle;
private RectF mRect;
private ArgbEvaluator mArgbEvaluator;
private Thread uiThread;
public CircleProgressBar(Context context) {
this(context, null, 0);
}
public CircleProgressBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public CircleProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomProgressBar, defStyleAttr, 0);
init(typedArray);
}
private void init(TypedArray typedArray){
mTickSplitAngle = typedArray.getDimension(R.styleable.CustomProgressBar_tick_split_angle, TICK_SPLIT_DEFAULT_ANGLE);
mNormalTickSize = typedArray.getDimension(R.styleable.CustomProgressBar_normal_tick_size, NORMAL_TICK_DEFAULT_SIZE);
mCurrentTickSize = typedArray.getDimension(R.styleable.CustomProgressBar_current_tick_size, CURRENT_TICK_DEFAULT_SIZE);
mBlockAngle =typedArray.getDimension(R.styleable.CustomProgressBar_tick_block_angle, TICK_BLOCK_DEFAULT_ANGLE);
mGradientStartColor = typedArray.getColor(R.styleable.CustomProgressBar_gradient_start_color, GRADIENT_START_DEFAULT_COLOR);
mGradientEndColor = typedArray.getColor(R.styleable.CustomProgressBar_gradient_start_color, GRADIENT_END_DEFAULT_COLOR);
mTickNormalColor = typedArray.getColor(R.styleable.CustomProgressBar_tick_normal_color, TICK_NORMAL_DEFAULT_COLOR);
typedArray.recycle();
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setStyle(Paint.Style.STROKE);
mTotalTickCount = (int)( 360f /(mTickSplitAngle+mBlockAngle));//确保刻度数量为整数
uiThread=Thread.currentThread();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = measureHanlder(widthMeasureSpec);
int height = measureHanlder(heightMeasureSpec);
mCircleWidth = (width < height) ? width : height;
setMeasuredDimension(mCircleWidth, mCircleWidth);
float padding = mCurrentTickSize/2;
mRect = new RectF(padding, padding, mCircleWidth-padding, mCircleWidth-padding);
mArgbEvaluator = new ArgbEvaluator();
}
private int measureHanlder(int measureSpec){
int result = 0;
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
if (specMode == MeasureSpec.EXACTLY) {
result = specSize;
} else if (specMode == MeasureSpec.AT_MOST) {
result = Math.max(result, specSize);
}
return result;
}
@Override
protected void onDraw(Canvas canvas) {
final int currentBlockIndex =(int) (mCurrentProgressPercent / 100f * mTotalTickCount);
for (int i = 0; i < mTotalTickCount; i++) {
if(i == currentBlockIndex -1){
//当前刻度,刻度长度较长
mPaint.setStrokeWidth(mCurrentTickSize);
mPaint.setColor((Integer) mArgbEvaluator.evaluate(i * (mBlockAngle + mTickSplitAngle)/(360), mGradientStartColor ,mGradientEndColor));
}else if( i < currentBlockIndex){
//已选中的刻度
mPaint.setStrokeWidth(mNormalTickSize);
mPaint.setColor((Integer) mArgbEvaluator.evaluate(i * (mBlockAngle + mTickSplitAngle)/(360), mGradientStartColor ,mGradientEndColor));
}
else {
//未选中的刻度
mPaint.setStrokeWidth(mNormalTickSize);
mPaint.setColor(mTickNormalColor);
}
canvas.drawArc(mRect, i * (mBlockAngle + mTickSplitAngle), mBlockAngle, false, mPaint);
}
}
/**
* 设置进度
* @param percent 百分百
*/
public void setProgress(int percent){
mCurrentProgressPercent =percent;
synchronized (lock){
if(Thread.currentThread() != uiThread){
postInvalidate();
}
else{
invalidate();
}
}
}
}
是不是很简单,用不了五分钟 _完整demo请看Github
网友评论