公司项目想做个渐变效果,最终实现方案
public class FanProgressBar extends View {
/**
* 画笔对象的引用
*/
private Paint circlePaint; //底部圆环画笔
private Paint arcPaint; //上部圆弧画笔
private Paint topCirclePoint; //顶部圆点
private Path mPath;
private boolean capRound; //画笔形状
private int roundColor; //圆环的颜色
private int roundProgressColor; //圆弧进度的颜色
private float roundWidth; //圆环的宽度
private int maxProgress = 100; //最大进度
private float progress; //当前进度
private int style = STROKE; //进度的风格,实心或者空心
public static final int STROKE = 0;
public static final int FILL = 1;
public FanProgressBar(Context context) {
this(context, null);
}
public FanProgressBar(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FanProgressBar(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.FanProgressBar);
// 获取自定义属性和默认值
roundColor = mTypedArray.getColor(R.styleable.FanProgressBar_bgColor, Color.RED);
roundProgressColor = mTypedArray.getColor(R.styleable.FanProgressBar_fgColor, Color.GREEN);
roundWidth = mTypedArray.getDimension(R.styleable.FanProgressBar_fanRoundWidth, DensityUtil.dip2px(getContext(), 15));
progress = mTypedArray.getInt(R.styleable.FanProgressBar_fanProgress, 0);
capRound = mTypedArray.getBoolean(R.styleable.FanProgressBar_capRound, true);
mTypedArray.recycle();
}
private RectF mOval;
private SweepGradient sweepGradient;
private List<Integer> colorList = new ArrayList<>();
private static final int[] colors = new int[]{Color.GREEN, Color.GREEN, Color.BLUE, Color.RED, Color.RED};
private float circleSize;
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
float size = Math.min(w, h);
circleSize = size;
mOval = new RectF(roundWidth / 2, roundWidth / 2, size - roundWidth / 2, size - roundWidth / 2);
init();
}
/**
* 初始化操作
*/
private void init() {
circlePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
circlePaint.setColor(roundColor); // 设置圆环的颜色
circlePaint.setStyle(Paint.Style.STROKE); // 设置空心
circlePaint.setStrokeWidth(roundWidth); // 设置圆环的宽度
circlePaint.setAntiAlias(true); // 消除锯齿
circlePaint.setStrokeCap(capRound ? Paint.Cap.ROUND : Paint.Cap.SQUARE);
int[] colors = new int[colorList.size()];
for (int i = 0; i < colors.length; i++) {
colors[i] = colorList.get(i);
}
sweepGradient = new SweepGradient(mOval.centerX(), mOval.centerY(), colors, null);
arcPaint = new Paint();
// arcPaint.setColor(roundProgressColor); // 设置圆环的颜色
arcPaint.setStyle(Paint.Style.STROKE); // 设置空心
arcPaint.setStrokeWidth(roundWidth); // 设置圆环的宽度
arcPaint.setAntiAlias(true); // 消除锯齿
arcPaint.setStrokeCap(capRound ? Paint.Cap.ROUND : Paint.Cap.SQUARE);
arcPaint.setShader(sweepGradient);
mPath = new Path();
// mPath.reset();
// mPath.addArc(mOval, 30, maxProgress);
topCirclePoint = new Paint();
topCirclePoint.setColor(ContextCompat.getColor(getContext(), R.color.white)); // 设置圆环的颜色
topCirclePoint.setStyle(Paint.Style.FILL_AND_STROKE);
topCirclePoint.setAntiAlias(true); // 消除锯齿
}
/**
* 调用canvas.restore()方法之前必须先调用canvas.save()方法, 不然会报错
* canvas的save 和 restore是成对使用(restore只能比save少,不能多)
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawArc(mOval, 0, 360, false, circlePaint); // 画出圆环
//画圆弧, 画圆环的进度
canvas.save();
float perimeter = mOval.width() * (float) Math.PI; //diameter 直径 radius 半径
float deltaDegree = roundWidth / 2 / perimeter * 360;
//避免由于Paint设置StrokeCap为ROUND而引起的颜色延伸
// deltaDegree = 30;
canvas.rotate(-90 - deltaDegree, circleSize / 2, circleSize / 2);
switch (style) {
case STROKE: {
// Paint p = new Paint();
// 参数一为渐变起初点坐标x位置,参数二为y轴位置,参数三和四分辨对应渐变终点,最后参数为平铺方式,这里设置为镜像
// Gradient是基于Shader类,所以我们通过Paint的setShader方法来设置这个渐变
// LinearGradient lg = new LinearGradient(0, 0, 400, 400, colors, positions, Shader.TileMode.MIRROR);
// arcPaint.setShader(lg);
// mPath.reset();
// mPath.addArc(mOval, 30, progress);
// canvas.drawPath(mPath, arcPaint);
canvas.drawArc(mOval, deltaDegree, progress, false, arcPaint); // 根据进度画圆弧
break;
}
case FILL: {
arcPaint.setStyle(Paint.Style.FILL_AND_STROKE);
if (progress != 0)
canvas.drawArc(mOval, 0, 360 * progress / maxProgress, true, arcPaint); // 根据进度画圆弧
break;
}
}
canvas.restore();
//
// //保存之后,再旋转回原来的角度,这样白色小圆点就可以显示在圆环顶部了
// canvas.rotate(90 + deltaDegree, circleSize / 2, circleSize / 2);
canvas.drawCircle(mOval.centerX(), roundWidth / 2, DensityUtil.dip2px(getContext(), 4), topCirclePoint);
}
/**
* 获取进度.需要同步
*/
public synchronized float getProgress() {
return progress;
}
public void setMaxProgress(int maxProgress) {
this.maxProgress = maxProgress;
colorList.clear();
for (int color : colors) {
colorList.add(color);
}
//将颜色值按比例分配到360个degree里面,不够的部分填充为其他颜色,反正也是显示不出来的,因为最大进度就那么多
float percent = maxProgress / 360f;
int maxSize = (int) ((colorList.size() / percent) + 0.5);
if (maxSize > colorList.size()) {
for (int i = 0; i < maxSize - colorList.size(); i++) {
colorList.add(Color.YELLOW);
}
}
}
public int getMaxProgress() {
return maxProgress;
}
/**
* 设置进度,此为线程安全控件,由于考虑多线的问题,需要同步 刷新界面调用postInvalidate()能在非UI线程刷新
*/
public void setProgress(int progress) {
if (progress < 0) {
progress = 0;
}
if (progress > maxProgress) {
progress = maxProgress;
}
setAnimation(progress);
}
/**
* 为进度设置动画
*/
public void setAnimation(float progress) {
ValueAnimator progressAnimator = ValueAnimator.ofFloat(0, progress);
progressAnimator.setDuration(3000);
progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
FanProgressBar.this.progress = (float) animation.getAnimatedValue();
invalidate();
}
});
progressAnimator.start();
}
}
public void setMaxProgress(int maxProgress) {
this.maxProgress = maxProgress;
colorList.clear();
for (int color : colors) {
colorList.add(color);
}
//将颜色值按比例分配到360个degree里面,不够的部分填充为其他颜色,反正也是显示不出来的,因为最大进度就那么多
float percent = maxProgress / 360f;
int maxSize = (int) ((colorList.size() / percent) + 0.5);
if (maxSize > colorList.size()) {
for (int i = 0; i < maxSize - colorList.size(); i++) {
colorList.add(Color.YELLOW);
}
}
}