自定义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>