一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

Android编程基于自定义View实现绚丽的圆形进度条功能示例

时间:2017-02-27 编辑:简简单单 来源:一聚教程网

本文实例讲述了Android编程基于自定义View实现绚丽的圆形进度条功能。分享给大家供大家参考,具体如下:

本文包含两个组件,首先上效果图:

1.ProgressBarView1(支持拖动):

2.ProgressBarView2(不同进度值显示不同颜色,不支持拖拽):

 

代码不多,注释也比较详细,全部贴上了:

(一)ProgressBarView1:

 

 代码如下 复制代码

/**

 * 自定义绚丽的ProgressBar.

 */

publicclassProgressBarView1extendsView {

  /**

   * 进度条所占用的角度

   */

  privatestaticfinalintARC_FULL_DEGREE =300;

  /**

   * 弧线的宽度

   */

  privateintSTROKE_WIDTH;

  /**

   * 组件的宽,高

   */

  privateintwidth, height;

  /**

   * 进度条最大值和当前进度值

   */

  privatefloatmax, progress;

  /**

   * 是否允许拖动进度条

   */

  privatebooleandraggingEnabled =false;

  /**

   * 绘制弧线的矩形区域

   */

  privateRectF circleRectF;

  /**

   * 绘制弧线的画笔

   */

  privatePaint progressPaint;

  /**

   * 绘制文字的画笔

   */

  privatePaint textPaint;

  /**

   * 绘制当前进度值的画笔

   */

  privatePaint thumbPaint;

  /**

   * 圆弧的半径

   */

  privateintcircleRadius;

  /**

   * 圆弧圆心位置

   */

  privateintcenterX, centerY;

  publicProgressBarView1(Context context) {

    super(context);

    init();

  }

  publicProgressBarView1(Context context, AttributeSet attrs) {

    super(context, attrs);

    init();

  }

  publicProgressBarView1(Context context, AttributeSet attrs,intdefStyleAttr) {

    super(context, attrs, defStyleAttr);

    init();

  }

  privatevoidinit() {

    progressPaint =newPaint();

    progressPaint.setAntiAlias(true);

    textPaint =newPaint();

    textPaint.setColor(Color.WHITE);

    textPaint.setAntiAlias(true);

    thumbPaint =newPaint();

    thumbPaint.setAntiAlias(true);

    //使用自定义字体

    textPaint.setTypeface(Typeface.createFromAsset(getContext().getAssets(),"fangz.ttf"));

  }

  @Override

  protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec) {

    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    if(width ==0|| height ==0) {

      width = getWidth();

      height = getHeight();

      //计算圆弧半径和圆心点

      circleRadius = Math.min(width, height) /2;

      STROKE_WIDTH = circleRadius /12;

      circleRadius -= STROKE_WIDTH;

      centerX = width /2;

      centerY = height /2;

      //圆弧所在矩形区域

      circleRectF =newRectF();

      circleRectF.left = centerX - circleRadius;

      circleRectF.top = centerY - circleRadius;

      circleRectF.right = centerX + circleRadius;

      circleRectF.bottom = centerY + circleRadius;

    }

  }

  privateRect textBounds =newRect();

  @Override

  protectedvoidonDraw(Canvas canvas) {

    super.onDraw(canvas);

    floatstart =90+ ((360- ARC_FULL_DEGREE) >>1);//进度条起始点

    floatsweep1 = ARC_FULL_DEGREE * (progress / max);//进度划过的角度

    floatsweep2 = ARC_FULL_DEGREE - sweep1;//剩余的角度

    //绘制起始位置小圆形

    progressPaint.setColor(Color.WHITE);

    progressPaint.setStrokeWidth(0);

    progressPaint.setStyle(Paint.Style.FILL);

    floatradians = (float) (((360.0f - ARC_FULL_DEGREE) /2) /180* Math.PI);

    floatstartX = centerX - circleRadius * (float) Math.sin(radians);

    floatstartY = centerY + circleRadius * (float) Math.cos(radians);

    canvas.drawCircle(startX, startY, STROKE_WIDTH /2, progressPaint);

    //绘制进度条

    progressPaint.setStrokeWidth(STROKE_WIDTH);

    progressPaint.setStyle(Paint.Style.STROKE);//设置空心

    canvas.drawArc(circleRectF, start, sweep1,false, progressPaint);

    //绘制进度条背景

    progressPaint.setColor(Color.parseColor("#d64444"));

    canvas.drawArc(circleRectF, start + sweep1, sweep2,false, progressPaint);

    //绘制结束位置小圆形

    progressPaint.setStrokeWidth(0);

    progressPaint.setStyle(Paint.Style.FILL);

    floatendX = centerX + circleRadius * (float) Math.sin(radians);

    floatendY = centerY + circleRadius * (float) Math.cos(radians);

    canvas.drawCircle(endX, endY, STROKE_WIDTH /2, progressPaint);

    //上一行文字

    textPaint.setTextSize(circleRadius >>1);

    String text = (int) (100* progress / max) +"";

    floattextLen = textPaint.measureText(text);

    //计算文字高度

    textPaint.getTextBounds("8",0,1, textBounds);

    floath1 = textBounds.height();

    //% 前面的数字水平居中,适当调整

    floatextra = text.startsWith("1") ? -textPaint.measureText("1") /2:0;

    canvas.drawText(text, centerX - textLen /2+ extra, centerY -30+ h1 /2, textPaint);

    //百分号

    textPaint.setTextSize(circleRadius >>2);

    canvas.drawText("%", centerX + textLen /2+ extra +5, centerY -30+ h1 /2, textPaint);

    //下一行文字

    textPaint.setTextSize(circleRadius /5);

    text ="可用内存充足";

    textLen = textPaint.measureText(text);

    textPaint.getTextBounds(text,0, text.length(), textBounds);

    floath2 = textBounds.height();

    canvas.drawText(text, centerX - textLen /2, centerY + h1 /2+ h2, textPaint);

    //绘制进度位置,也可以直接替换成一张图片

    floatprogressRadians = (float) (((360.0f - ARC_FULL_DEGREE) /2+ sweep1) /180* Math.PI);

    floatthumbX = centerX - circleRadius * (float) Math.sin(progressRadians);

    floatthumbY = centerY + circleRadius * (float) Math.cos(progressRadians);

    thumbPaint.setColor(Color.parseColor("#33d64444"));

    canvas.drawCircle(thumbX, thumbY, STROKE_WIDTH *2.0f, thumbPaint);

    thumbPaint.setColor(Color.parseColor("#99d64444"));

    canvas.drawCircle(thumbX, thumbY, STROKE_WIDTH *1.4f, thumbPaint);

    thumbPaint.setColor(Color.WHITE);

    canvas.drawCircle(thumbX, thumbY, STROKE_WIDTH *0.8f, thumbPaint);

  }

  privatebooleanisDragging =false;

  @Override

  publicbooleanonTouchEvent(@NonNullMotionEvent event) {

    if(!draggingEnabled) {

      returnsuper.onTouchEvent(event);

    }

    //处理拖动事件

    floatcurrentX = event.getX();

    floatcurrentY = event.getY();

    intaction = event.getAction();

    switch(action) {

      caseMotionEvent.ACTION_DOWN:

        //判断是否在进度条thumb位置

        if(checkOnArc(currentX, currentY)) {

          floatnewProgress = calDegreeByPosition(currentX, currentY) / ARC_FULL_DEGREE * max;

          setProgressSync(newProgress);

          isDragging =true;

        }

        break;

      caseMotionEvent.ACTION_MOVE:

        if(isDragging) {

          //判断拖动时是否移出去了

          if(checkOnArc(currentX, currentY)) {

            setProgressSync(calDegreeByPosition(currentX, currentY) / ARC_FULL_DEGREE * max);

          }else{

            isDragging =false;

          }

        }

        break;

      caseMotionEvent.ACTION_UP:

        isDragging =false;

        break;

    }

    returntrue;

  }

  privatefloatcalDistance(floatx1,floaty1,floatx2,floaty2) {

    return(float) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));

  }

  /**

   * 判断该点是否在弧线上(附近)

   */

  privatebooleancheckOnArc(floatcurrentX,floatcurrentY) {

    floatdistance = calDistance(currentX, currentY, centerX, centerY);

    floatdegree = calDegreeByPosition(currentX, currentY);

    returndistance > circleRadius - STROKE_WIDTH *5&& distance < circleRadius + STROKE_WIDTH *5

        && (degree >= -8&& degree <= ARC_FULL_DEGREE +8);

  }

  /**

   * 根据当前位置,计算出进度条已经转过的角度。

   */

  privatefloatcalDegreeByPosition(floatcurrentX,floatcurrentY) {

    floata1 = (float) (Math.atan(1.0f * (centerX - currentX) / (currentY - centerY)) / Math.PI *180);

    if(currentY < centerY) {

      a1 +=180;

    }elseif(currentY > centerY && currentX > centerX) {

      a1 +=360;

    }

    returna1 - (360- ARC_FULL_DEGREE) /2;

  }

  publicvoidsetMax(intmax) {

    this.max = max;

    invalidate();

  }

  publicvoidsetProgress(floatprogress) {

    finalfloatvalidProgress = checkProgress(progress);

    //动画切换进度值

    newThread(newRunnable() {

      @Override

      publicvoidrun() {

        floatoldProgress = ProgressBarView1.this.progress;

        for(inti =1; i <=100; i++) {

          ProgressBarView1.this.progress = oldProgress + (validProgress - oldProgress) * (1.0f * i /100);

          postInvalidate();

          SystemClock.sleep(20);

        }

      }

    }).start();

  }

  publicvoidsetProgressSync(floatprogress) {

    this.progress = checkProgress(progress);

    invalidate();

  }

  //保证progress的值位于[0,max]

  privatefloatcheckProgress(floatprogress) {

    if(progress <0) {

      return0;

    }

    returnprogress > max ? max : progress;

  }

  publicvoidsetDraggingEnabled(booleandraggingEnabled) {

    this.draggingEnabled = draggingEnabled;

  }

}

 

(二)ProgressBarView2:

 

 代码如下 复制代码

/**

 * 自定义绚丽的ProgressBar.

 */

publicclassProgressBarView2extendsView {

  /**

   * 进度条所占用的角度

   */

  privatestaticfinalintARC_FULL_DEGREE =300;

  //进度条个数

  privatestaticfinalintCOUNT =100;

  //每个进度条所占用角度

  privatestaticfinalfloatARC_EACH_PROGRESS = ARC_FULL_DEGREE *1.0f / (COUNT -1);

  /**

   * 弧线细线条的长度

   */

  privateintARC_LINE_LENGTH;

  /**

   * 弧线细线条的宽度

   */

  privateintARC_LINE_WIDTH;

  /**

   * 组件的宽,高

   */

  privateintwidth, height;

  /**

   * 进度条最大值和当前进度值

   */

  privatefloatmax, progress;

  /**

   * 绘制弧线的画笔

   */

  privatePaint progressPaint;

  /**

   * 绘制文字的画笔

   */

  privatePaint textPaint;

  /**

   * 绘制文字背景圆形的画笔

   */

  privatePaint textBgPaint;

  /**

   * 圆弧的半径

   */

  privateintcircleRadius;

  /**

   * 圆弧圆心位置

   */

  privateintcenterX, centerY;

  publicProgressBarView2(Context context) {

    super(context);

    init();

  }

  publicProgressBarView2(Context context, AttributeSet attrs) {

    super(context, attrs);

    init();

  }

  publicProgressBarView2(Context context, AttributeSet attrs,intdefStyleAttr) {

    super(context, attrs, defStyleAttr);

    init();

  }

  privatevoidinit() {

    progressPaint =newPaint();

    progressPaint.setAntiAlias(true);

    textPaint =newPaint();

    textPaint.setColor(Color.WHITE);

    textPaint.setAntiAlias(true);

    textBgPaint =newPaint();

    textBgPaint.setAntiAlias(true);

  }

  @Override

  protectedvoidonMeasure(intwidthMeasureSpec,intheightMeasureSpec) {

    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

    if(width ==0|| height ==0) {

      width = getWidth();

      height = getHeight();

      //计算圆弧半径和圆心点

      circleRadius = Math.min(width, height) /2;

      ARC_LINE_LENGTH = circleRadius /6;

      ARC_LINE_WIDTH = ARC_LINE_LENGTH /8;

      centerX = width /2;

      centerY = height /2;

    }

  }

  privateRect textBounds =newRect();

  @Override

  protectedvoidonDraw(Canvas canvas) {

    super.onDraw(canvas);

    floatstart = (360- ARC_FULL_DEGREE) >>1;//进度条起始角度

    floatsweep1 = ARC_FULL_DEGREE * (progress / max);//进度划过的角度

    //绘制进度条

    progressPaint.setColor(Color.parseColor(calColor(progress / max,"#ffff0000","#ff00ff00")));

    progressPaint.setStrokeWidth(ARC_LINE_WIDTH);

    floatdrawDegree =1.6f;

    while(drawDegree <= ARC_FULL_DEGREE) {

      doublea = (start + drawDegree) /180* Math.PI;

      floatlineStartX = centerX - circleRadius * (float) Math.sin(a);

      floatlineStartY = centerY + circleRadius * (float) Math.cos(a);

      floatlineStopX = lineStartX + ARC_LINE_LENGTH * (float) Math.sin(a);

      floatlineStopY = lineStartY - ARC_LINE_LENGTH * (float) Math.cos(a);

      if(drawDegree > sweep1) {

        //绘制进度条背景

        progressPaint.setColor(Color.parseColor("#88aaaaaa"));

        progressPaint.setStrokeWidth(ARC_LINE_WIDTH >>1);

      }

      canvas.drawLine(lineStartX, lineStartY, lineStopX, lineStopY, progressPaint);

      drawDegree += ARC_EACH_PROGRESS;

    }

    //绘制文字背景圆形

    textBgPaint.setStyle(Paint.Style.FILL);//设置填充

    textBgPaint.setColor(Color.parseColor("#41668b"));

    canvas.drawCircle(centerX, centerY, (circleRadius - ARC_LINE_LENGTH) *0.8f, textBgPaint);

    textBgPaint.setStyle(Paint.Style.STROKE);//设置空心

    textBgPaint.setStrokeWidth(2);

    textBgPaint.setColor(Color.parseColor("#aaaaaaaa"));

    canvas.drawCircle(centerX, centerY, (circleRadius - ARC_LINE_LENGTH) *0.8f, textBgPaint);

    //上一行文字

    textPaint.setTextSize(circleRadius >>1);

    String text = (int) (100* progress / max) +"";

    floattextLen = textPaint.measureText(text);

    //计算文字高度

    textPaint.getTextBounds("8",0,1, textBounds);

    floath1 = textBounds.height();

    canvas.drawText(text, centerX - textLen /2, centerY - circleRadius /10+ h1 /2, textPaint);

    //分

    textPaint.setTextSize(circleRadius >>3);

    textPaint.getTextBounds("分",0,1, textBounds);

    floath11 = textBounds.height();

    canvas.drawText("分", centerX + textLen /2+5, centerY - circleRadius /10+ h1 /2- (h1 - h11), textPaint);

    //下一行文字

    textPaint.setTextSize(circleRadius /6);

    text ="点击优化";

    textLen = textPaint.measureText(text);

    canvas.drawText(text, centerX - textLen /2, centerY + circleRadius /2.5f, textPaint);

  }

  publicvoidsetMax(intmax) {

    this.max = max;

    invalidate();

  }

  //动画切换进度值(异步)

  publicvoidsetProgress(finalfloatprogress) {

    newThread(newRunnable() {

      @Override

      publicvoidrun() {

        floatoldProgress = ProgressBarView2.this.progress;

        for(inti =1; i <=100; i++) {

          ProgressBarView2.this.progress = oldProgress + (progress - oldProgress) * (1.0f * i /100);

          postInvalidate();

          SystemClock.sleep(20);

        }

      }

    }).start();

  }

  //直接设置进度值(同步)

  publicvoidsetProgressSync(floatprogress) {

    this.progress = progress;

    invalidate();

  }

  /**

   * 计算渐变效果中间的某个颜色值。

   * 仅支持 #aarrggbb 模式,例如 #ccc9c9b2

   */

  publicString calColor(floatfraction, String startValue, String endValue) {

    intstart_a, start_r, start_g, start_b;

    intend_a, end_r, end_g, end_b;

    //start

    start_a = getIntValue(startValue,1,3);

    start_r = getIntValue(startValue,3,5);

    start_g = getIntValue(startValue,5,7);

    start_b = getIntValue(startValue,7,9);

    //end

    end_a = getIntValue(endValue,1,3);

    end_r = getIntValue(endValue,3,5);

    end_g = getIntValue(endValue,5,7);

    end_b = getIntValue(endValue,7,9);

    return"#"+ getHexString((int) (start_a + fraction * (end_a - start_a)))

        + getHexString((int) (start_r + fraction * (end_r - start_r)))

        + getHexString((int) (start_g + fraction * (end_g - start_g)))

        + getHexString((int) (start_b + fraction * (end_b - start_b)));

  }

  //从原始#AARRGGBB颜色值中指定位置截取,并转为int.

  privateintgetIntValue(String hexValue,intstart,intend) {

    returnInteger.parseInt(hexValue.substring(start, end),16);

  }

  privateString getHexString(intvalue) {

    String a = Integer.toHexString(value);

    if(a.length() ==1) {

      a ="0"+ a;

    }

    returna;

  }

}

 

热门栏目