自定义View之—渐变进度条
龙行天下
8年前
<p>最近项目中用到渐变圆环进度条,自己也写了一下,用到一些知识,以前没有用过,使用过程中有一些问题,在此做一下笔记。</p> <p>渐变颜色其实用到的是颜色数组,然后根据数组计算来的,当然计算是Android系统进行的,不需要我们手动计算,我们只需要设置颜色数组和颜色值对应位置即可。画圆形渐变用到一个属性:SweepGradient,他的父类是一个Shader,</p> <p>由官方文档看到他有两个构造函数:</p> <pre> <code class="language-java">SweepGradient(float cx, float cy, int color0, int color1) SweepGradient(float cx, float cy, int colors[], float positions[]) </code></pre> <ul> <li>cx:要画的圆环的中心点x坐标;</li> <li>cy:要画的圆环的中心点y坐标;</li> <li>color0:起始颜色值;</li> <li>color1:结束颜色值;</li> <li>colors[]:颜色数组;</li> <li>positions[]:对应颜色值的位置,与颜色值数组个数相等,里面的值均为(0–1)的数字。</li> </ul> <p>先看一张效果图(图一):</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/5a944f913f59ebd0fffadab6b6274c0f.png"></p> <p>这就是一张渐变圆环图,上面的箭头和数字后面解释。</p> <p>我们主要研究第二个构造函数,颜色数组和颜色位置的使用方法。</p> <p>首先看一个例子:</p> <pre> <code class="language-java">/** * 圆形渐变进度条 * 相关知识: * <p> * Created by yuchuan on 16/9/29. */ public class CircleGradientProgressbar extends View { private final static int DURATION = 3000; private int mWidth; private int mHeight; private int mDiam; private int mColorGreen; private int mColorYellow; private int mColorRed; private final float mMaxProgress = 100f; //默认进度 private int mProgress = 80; private int mCurrentProgress = 100; //进图条圆环宽度 private int mProgressStrokeWidth = 10; //进度条背景画笔 private Paint mCirclePaint; //进度条画笔 private Paint mProgressPaint; private Shader mProgressShader; //画圆所在的距形区域 private RectF mProgressOval; private ValueAnimator mAnimator; public CircleGradientProgressbar(Context context) { this(context, null); } public CircleGradientProgressbar(Context context, AttributeSet attrs) { super(context, attrs); init(); } private void init() { mColorGreen = getResources().getColor(R.color.mx_circle_progressbar_green); mColorYellow = getResources().getColor(R.color.mx_circle_progressbar_orange); mColorRed = getResources().getColor(R.color.mx_circle_progressbar_red); mProgressOval = new RectF(); mCirclePaint = new Paint(); mCirclePaint.setAntiAlias(true); mCirclePaint.setColor(Color.GRAY); mProgressPaint = new Paint(); //设置抗锯齿 mProgressPaint.setAntiAlias(true); //设置笔为圆角 // mProgressPaint.setStrokeCap(Paint.Cap.ROUND); mProgressPaint.setStyle(Paint.Style.STROKE); mAnimator = ValueAnimator.ofFloat(0, 1f); mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float percent = (float) animation.getAnimatedValue(); if (percent > 0) { mCurrentProgress = (int) (mProgress * percent); postInvalidate(); } } }); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mWidth = getWidth(); mHeight = getHeight(); mDiam = Math.min(mWidth, mHeight); mProgressStrokeWidth = mDiam / 6; drawCircle(canvas); drawSweepProgressBar(canvas, mWidth / 2, mHeight / 2); } private void drawCircle(Canvas canvas) { canvas.drawArc(mProgressOval, 0, 360, false, mCirclePaint); } /** * 画渐变圆环: * colorSweep[]: 渐变颜色数组 * position[]: 每个颜色值的相对位置,个数与颜色数组个数相等 * 注:位置与渐变颜色值的设置教程见博客: * * @param canvas 画布 * @param cx 圆环中心X坐标 * @param cy 圆环中心Y坐标 */ private void drawSweepProgressBar(Canvas canvas, int cx, float cy) { //设置圆环的大小 mProgressOval.top = cy - mDiam / 4; mProgressOval.left = cx - mDiam / 4; mProgressOval.bottom = cy + mDiam / 4; mProgressOval.right = cx + mDiam / 4; //画渐变颜色 int colorSweep[] = {mColorGreen, mColorYellow, mColorRed}; float position[] = {0f,0.5f,0.7f}; mProgressShader = new SweepGradient(cx, cy, colorSweep, position); mProgressPaint.setShader(mProgressShader); mProgressPaint.setStrokeWidth(mProgressStrokeWidth); canvas.drawArc(mProgressOval, 0, ((float) mCurrentProgress / mMaxProgress) * 360, false, mProgressPaint); // 绘制进度圆弧,这里是蓝色 } public void setProgress(int progress) { this.mProgress = progress; if (mAnimator != null && progress > 0) { if (mAnimator.isRunning()) { return; } mAnimator.setDuration((long) (DURATION / mMaxProgress * progress)); mAnimator.start(); } } } </code></pre> <p>效果图如下:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/cc8c0afde1e63376fff4a891f9c6c953.png"></p> <p>此时的颜色数组和位置参数为:</p> <pre> <code class="language-java">int colorSweep[] = {mColorGreen, mColorYellow, mColorRed}; float position[] = {0f,0.5f,0.7f}; </code></pre> <p>下面我们更改一下颜色值的位置:</p> <pre> <code class="language-java">int colorSweep[] = {mColorGreen, mColorYellow, mColorRed}; float position[] = {0.25f,0.5f,0.75f}; </code></pre> <p>效果图如下:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/83cc4e1eb4376a6becc260244102bfde.png"></p> <p>对比上面两个图片我们看到随着第一个位置的值的增大,第一个颜色值的渐变色开始位置也在向后移动。此时我们画圆环是从0度开始的,也就是3点钟的位置开始,顺时针开始画圆环。第一个颜色绿色也是从这个位置开始的。那么我们看看如果我改变开始画的位置,有什么变化吗?</p> <p>我用上面第二组的数据,然后只改变画圆环的初始位置:</p> <pre> <code class="language-java">int colorSweep[] = {mColorGreen, mColorYellow, mColorRed}; float position[] = {0.25f,0.5f,0.75f}; canvas.drawArc(mProgressOval, 0, ((float) mCurrentProgress / mMaxProgress) * 360, false, mProgressPaint); </code></pre> <p>效果图如下:</p> <p><img src="https://simg.open-open.com/show/1c49a79fb7b820144a1d1548a2fa2bd4.png" alt="自定义View之—渐变进度条" width="480" height="484"></p> <p>显示效果和上面一个是一样的,只是运行时你会发现,圆环是从(图一)0.75那个位置开始顺时针画的,并且开始画的颜色是红色的,由此判断,第一个颜色值是用(图一)0的那个位置顺时针开始计算的,那么如果我想从0.75那个位置开始画并且颜色从绿的开始怎么画,那你需要将开始画的角度改为:-90,然后更改颜色数组和颜色位置数组:</p> <pre> <code class="language-java">int colorSweep[] = {mColorGreen, mColorGreen, mColorYellow, mColorRed, mColorGreen, mColorGreen}; float position[] = {0.1f, 0.25f, 0.5f, 0.751f, 0.75f, 1f}; canvas.drawArc(mProgressOval, -90, ((float) mCurrentProgress / mMaxProgress) * 360, false, mProgressPaint); </code></pre> <p>效果图如下:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/1d2c19e2eedccdaf64981a23c653dc9a.png"></p> <p>此时我们看到,绿色是从(图一)0.75位置开始的,并且圆环也是从这个位置开始画的,但是此时我的颜色值和位置增加了,主要是后面部分,倒数第二个颜色值是绿色,对应位置是0.75,也是就分段设置颜色值,0.75的位置为绿色,最后一个也是绿色,则说明从0.75之后到1的位置都是绿色,然后0后面的颜色根据位置数组第一个参数开始计算,如果角度不是0就要按照这个计算进行调整。</p> <p>另外,最后一个例子中相同颜色设置了多个,这个是调节渐变和纯色位置的,也就是相同颜色位置间的颜色是纯色的,不同颜色值中间的颜色是过度的,自己可以调节一下掌握以下技巧。</p> <p> </p> <p> </p>