FanProgressBar,渐变的替代方案

公司项目想做个渐变效果,最终实现方案

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()方法, 不然会报错
     * canvassave 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设置StrokeCapROUND而引起的颜色延伸
//        deltaDegree = 30;
        canvas.rotate(-90 - deltaDegree, circleSize / 2, circleSize / 2);
        switch (style) {
            case STROKE: {
//                Paint p = new Paint();
//                参数一为渐变起初点坐标x位置,参数二为y轴位置,参数三和四分辨对应渐变终点,最后参数为平铺方式,这里设置为镜像
//                Gradient是基于Shader类,所以我们通过PaintsetShader方法来设置这个渐变
//                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);
        }

        //将颜色值按比例分配到360degree里面,不够的部分填充为其他颜色,反正也是显示不出来的,因为最大进度就那么多
        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);
    }

    //将颜色值按比例分配到360degree里面,不够的部分填充为其他颜色,反正也是显示不出来的,因为最大进度就那么多
    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);
        }
    }
}


效果如图:



猜你喜欢

转载自blog.csdn.net/tang_jian_1228/article/details/78845101
今日推荐