FanProgressBar,关于Canvas的一点体会

公司项目想做个渐变效果,虽然最终没有实现出来,还是把自己的一点体会写出来。算是根据现象推测实现吧,没去研究源码怎么实现的。

直接上代码:

package com.wedgits;

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.Path;
import android.graphics.RectF;
import android.graphics.SweepGradient;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.View;

import com.puhui.lib.utils.DensityUtil;
import com.renren.customview.R;

/**
 * Copyright: *******
 * Created by ******* on 2017/5/9.
 * Description:  环形进度
 * Modified By:
 */

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 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);

        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); // 消除锯齿
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.rotate(-120, circleSize / 2, circleSize / 2);

        canvas.save();
        canvas.drawArc(mOval, 0, 360, false, circlePaint); // 画出圆环

        //画圆弧 ,画圆环的进度
//        arcPaint.setColor(roundProgressColor); // 设置进度的颜色
//        arcPaint.setShader(sweepGradient);
        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, 30, 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.drawCircle(mOval.centerX(), roundWidth / 2, DensityUtil.dip2px(getContext(), 4), topCirclePoint);
        canvas.restore();
    }

    /**
     * 获取进度.需要同步
     */
    public synchronized float getProgress() {
        return progress;
    }

    public void setMaxProgress(int maxProgress) {
        this.maxProgress = maxProgress;
    }

    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();
    }
}
样式文件:
<declare-styleable name="FanProgressBar">
    <attr name="bgColor" format="color" />
    <attr name="fgColor" format="color" />
    <attr name="fanRoundWidth" format="dimension" />
    <attr name="fanProgress" format="integer" />
    <attr name="capRound" format="boolean" />
</declare-styleable>
使用:

LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) fanProgressBar.getLayoutParams();
layoutParams.width = DensityUtil.getScreenWidth(this) - DensityUtil.dip2px(this, 120);
layoutParams.height = DensityUtil.getScreenWidth(this) - DensityUtil.dip2px(this, 120);
fanProgressBar.setLayoutParams(layoutParams);
fanProgressBar.setMaxProgress(360);
fanProgressBar.setAnimation(fanProgressBar.getMaxProgress());

效果一:


效果二:


效果三:



效果四:(onDraw方法部分代码同效果三)


唉,纠结该怎么描述。

不管了,瞎说吧。

一、在我们给Paint设置shader(arcPaint.setShader(sweepGradient);)时,圆环的颜色占比就已经分配好了new int[]{Color.GREEN, Color.GREEN, Color.BLUE, Color.RED, Color.RED};,Green : Blue : Red = 2 : 1 : 2。而且是分配在整个圆环的。所以在Progress设置为360,200,120时,出现不同的效果,如效果一,效果四。


二、



猜你喜欢

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