Android|自定义横向带刻度progressbar

项目需要,需要自定义带渐变色的进度条,效果如下:
Android|自定义横向带刻度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 = https://www.it610.com/article/(float) animation.getAnimatedValue(); //不断的改变可变矩形的宽度 mProgressWidth = (int) (mAnimatorValue * mViewWidth); invalidate(); } }; mAnimator.addUpdateListener(mUpdateListener); mAnimator.start(); }

【Android|自定义横向带刻度progressbar】这里是一个大概的实现,完整代码。
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 = https://www.it610.com/article/(float) animation.getAnimatedValue(); mProgressWidth = (int) (mAnimatorValue * mViewWidth); invalidate(); } }; mAnimator.addUpdateListener(mUpdateListener); mAnimator.start(); } }

    推荐阅读