自定义横向带刻度progressbar

项目需要,需要自定义带渐变色的进度条,效果如下:

1,思路

  • 首先绘制 roundRect 带半圆的矩形背景
  • 绘制一个 可变的rect矩形 ,让rect的宽度不断的变大来实现对下面roundRect覆盖
  • 通过PorterDuffXfermode的PorterDuff.Mode.SRC_IN来取可变rect跟背景rect相交的部分
  • 记得取消硬件加速

2,用到的主要知识点

  • LinearGradient 渐变色
  • PorterDuffXfermode 去交集部分渲染

3,开始绘制

  • 1,初始化,onsizechange ,onMeasure省略…
  • 2,画背景跟边
  canvas.drawRoundRect(mBgRect, mViewHeight / 2, mViewHeight / 2, mBgPaint);
  canvas.drawRoundRect(mBgRect, mViewHeight / 2, mViewHeight / 2, mStrokePaint);
  • 3,初始化可变的rect矩形跟渐变色的shader
    //可变矩形mProgressWidth
  RectF progressRect = new RectF(mStrokeWidth / 2, mStrokeWidth / 2, mProgressWidth - mStrokeWidth / 2, mViewHeight - mStrokeWidth / 2);
    //渐变色的起始x,y;终点x,y;渐变色的开始,终止颜色,模式
 Shader mShader = new LinearGradient(mStrokeWidth / 2, mStrokeWidth / 2, mProgressWidth, mHeight - mStrokeWidth / 2, Color.parseColor("#27a6ff"), Color.parseColor("#099aff"), Shader.TileMode.REPEAT);
  • 4,绘制这个遮罩的rect
  //遮罩
        mProgressPaint.setXfermode(mXfermode);
        mProgressPaint.setShader(mShader);
        canvas.drawRect(progressRect, mProgressPaint);
    mProgressPaint.setXfermode(null);
  • 5,绘制刻度
//刻度
        for (int i = 0; i < mTickNums - 1; i++) {
            canvas.drawLine((i + 1) * mMackTickWidth, mStrokeWidth / 2, (i + 1) * mMackTickWidth, mViewHeight - mStrokeWidth / 2, mMackTickPaint);
        }  
  • 6,提供对外方法
    /**
     * progress取值范围[0-1]
     */
    public void setProgress(float progress) {
        if (progress < 0) {
            progress = 0;
        } else if (progress > 1) {
            progress = 1;
        }

        int delta = (int) (progress / 0.1);
        delta = delta == 0 ? 1 : delta;

        mAnimator = ValueAnimator.ofFloat(0, progress).setDuration(delta * DURATION);

        mUpdateListener = new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mAnimatorValue = (float) animation.getAnimatedValue();
                //不断的改变可变矩形的宽度
                mProgressWidth = (int) (mAnimatorValue * mViewWidth);
                invalidate();
            }
        };
        mAnimator.addUpdateListener(mUpdateListener);
        mAnimator.start();
    }

这里是一个大概的实现,完整代码。

public class TickProgress extends View {
    private static final long DURATION = 200;
    private int mViewWidth;
    private int mViewHeight;

    private int mStrokeWidth;

    private int mProgressWidth;

    private Paint mBgPaint;
    private Paint mProgressPaint;
    private Paint mMackTickPaint;


    private int mStrokeColor = Color.parseColor("#a3daff");

    private ValueAnimator.AnimatorUpdateListener mUpdateListener;
    private ValueAnimator mAnimator;
    // 动画数值(用于控制动画状态,因为同一时间内只允许有一种状态出现,具体数值处理取决于当前状态)
    private float mAnimatorValue;


    public TickProgress(Context context) {
        this(context, null);
    }

    public TickProgress(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    private Paint mStrokePaint;

    private int mHeight;

    public TickProgress(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mHeight = DisplayUtil.dip2px(context, 10);
        mStrokeWidth = DisplayUtil.dip2px(context, 1);
        mBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mBgPaint.setStyle(Paint.Style.FILL);
        mBgPaint.setStrokeWidth(mHeight);
        mBgPaint.setColor(Color.parseColor("#e6f6ff"));

        mStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mStrokePaint.setStyle(Paint.Style.STROKE);
        mStrokePaint.setStrokeWidth(mStrokeWidth);
        mStrokePaint.setColor(mStrokeColor);

        mProgressPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mProgressPaint.setStrokeWidth(mHeight);
        mProgressPaint.setStyle(Paint.Style.FILL);

        mMackTickPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mMackTickPaint.setStyle(Paint.Style.STROKE);
        mMackTickPaint.setStrokeWidth(mStrokeWidth);
        mMackTickPaint.setColor(mStrokeColor);

        setLayerType(LAYER_TYPE_HARDWARE, null);
    }

    private int mMackTickWidth;

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mViewHeight = h;
        mViewWidth = w;
        mMackTickWidth = w / 10;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(widthMeasureSpec, mHeight);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        RectF rectF2 = new RectF(mStrokeWidth, mStrokeWidth, mViewWidth - mStrokeWidth, mHeight - mStrokeWidth);

        canvas.drawRoundRect(rectF2, mHeight / 2, mHeight / 2, mBgPaint);
        canvas.drawRoundRect(rectF2, mHeight / 2, mHeight / 2, mStrokePaint);


        RectF rectF1 = new RectF(mStrokeWidth / 2, mStrokeWidth / 2, mProgressWidth - mStrokeWidth / 2, mViewHeight - mStrokeWidth / 2);
        Path path = new Path();

        Path dstPath = new Path();
        PathMeasure pathMeasure = new PathMeasure();
        path.moveTo(0, 0);
        path.lineTo(mViewWidth, 0);
        pathMeasure.setPath(path, false);
        pathMeasure.getSegment(0, pathMeasure.getLength() * mAnimatorValue, dstPath, true);
        //渐变
        Shader mShader = new LinearGradient(mStrokeWidth / 2, mStrokeWidth / 2, mProgressWidth, mHeight - mStrokeWidth / 2, Color.parseColor("#27a6ff"), Color.parseColor("#099aff"), Shader.TileMode.REPEAT);
        //遮罩
        mProgressPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
        mProgressPaint.setShader(mShader);
        canvas.drawRect(rectF1, mProgressPaint);
        mProgressPaint.setXfermode(null);
        //刻度
        for (int i = 0; i < 9; i++) {
            canvas.drawLine((i + 1) * mMackTickWidth, mStrokeWidth / 2, (i + 1) * mMackTickWidth, mViewHeight - mStrokeWidth / 2, mMackTickPaint);
        }
    }

    /**
     * 0--1
     */
    public void setProgress(float progress) {
        if (progress < 0) {
            progress = 0;
        } else if (progress > 1) {
            progress = 1;
        }

        int delta = (int) (progress /0.1);
        LogUtils.d("delta:"+delta);
        delta = delta == 0 ? 1 : delta;

        mProgressWidth = (int) (progress * mViewWidth);
        mAnimator = ValueAnimator.ofFloat(0, progress).setDuration(delta * DURATION);

        mUpdateListener = new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mAnimatorValue = (float) animation.getAnimatedValue();
                mProgressWidth = (int) (mAnimatorValue * mViewWidth);
                invalidate();
            }
        };
        mAnimator.addUpdateListener(mUpdateListener);
        mAnimator.start();
    }
}

你可能感兴趣的:(Android,自定义控件)