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

#技术教程 发布时间: 2026-01-18

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

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

1.ProgressBarView1(支持拖动):

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

 

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

(一)ProgressBarView1:

/**
 * 自定义绚丽的ProgressBar.
 */
public class ProgressBarView1 extends View {
  /**
   * 进度条所占用的角度
   */
  private static final int ARC_FULL_DEGREE = 300;
  /**
   * 弧线的宽度
   */
  private int STROKE_WIDTH;
  /**
   * 组件的宽,高
   */
  private int width, height;
  /**
   * 进度条最大值和当前进度值
   */
  private float max, progress;
  /**
   * 是否允许拖动进度条
   */
  private boolean draggingEnabled = false;
  /**
   * 绘制弧线的矩形区域
   */
  private RectF circleRectF;
  /**
   * 绘制弧线的画笔
   */
  private Paint progressPaint;
  /**
   * 绘制文字的画笔
   */
  private Paint textPaint;
  /**
   * 绘制当前进度值的画笔
   */
  private Paint thumbPaint;
  /**
   * 圆弧的半径
   */
  private int circleRadius;
  /**
   * 圆弧圆心位置
   */
  private int centerX, centerY;
  public ProgressBarView1(Context context) {
    super(context);
    init();
  }
  public ProgressBarView1(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
  }
  public ProgressBarView1(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init();
  }
  private void init() {
    progressPaint = new Paint();
    progressPaint.setAntiAlias(true);
    textPaint = new Paint();
    textPaint.setColor(Color.WHITE);
    textPaint.setAntiAlias(true);
    thumbPaint = new Paint();
    thumbPaint.setAntiAlias(true);
    //使用自定义字体
    textPaint.setTypeface(Typeface.createFromAsset(getContext().getAssets(), "fangz.ttf"));
  }
  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    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 = new RectF();
      circleRectF.left = centerX - circleRadius;
      circleRectF.top = centerY - circleRadius;
      circleRectF.right = centerX + circleRadius;
      circleRectF.bottom = centerY + circleRadius;
    }
  }
  private Rect textBounds = new Rect();
  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    float start = 90 + ((360 - ARC_FULL_DEGREE) >> 1); //进度条起始点
    float sweep1 = ARC_FULL_DEGREE * (progress / max); //进度划过的角度
    float sweep2 = ARC_FULL_DEGREE - sweep1; //剩余的角度
    //绘制起始位置小圆形
    progressPaint.setColor(Color.WHITE);
    progressPaint.setStrokeWidth(0);
    progressPaint.setStyle(Paint.Style.FILL);
    float radians = (float) (((360.0f - ARC_FULL_DEGREE) / 2) / 180 * Math.PI);
    float startX = centerX - circleRadius * (float) Math.sin(radians);
    float startY = 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);
    float endX = centerX + circleRadius * (float) Math.sin(radians);
    float endY = centerY + circleRadius * (float) Math.cos(radians);
    canvas.drawCircle(endX, endY, STROKE_WIDTH / 2, progressPaint);
    //上一行文字
    textPaint.setTextSize(circleRadius >> 1);
    String text = (int) (100 * progress / max) + "";
    float textLen = textPaint.measureText(text);
    //计算文字高度
    textPaint.getTextBounds("8", 0, 1, textBounds);
    float h1 = textBounds.height();
    //% 前面的数字水平居中,适当调整
    float extra = 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);
    float h2 = textBounds.height();
    canvas.drawText(text, centerX - textLen / 2, centerY + h1 / 2 + h2, textPaint);
    //绘制进度位置,也可以直接替换成一张图片
    float progressRadians = (float) (((360.0f - ARC_FULL_DEGREE) / 2 + sweep1) / 180 * Math.PI);
    float thumbX = centerX - circleRadius * (float) Math.sin(progressRadians);
    float thumbY = 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);
  }
  private boolean isDragging = false;
  @Override
  public boolean onTouchEvent(@NonNull MotionEvent event) {
    if (!draggingEnabled) {
      return super.onTouchEvent(event);
    }
    //处理拖动事件
    float currentX = event.getX();
    float currentY = event.getY();
    int action = event.getAction();
    switch (action) {
      case MotionEvent.ACTION_DOWN:
        //判断是否在进度条thumb位置
        if (checkOnArc(currentX, currentY)) {
          float newProgress = calDegreeByPosition(currentX, currentY) / ARC_FULL_DEGREE * max;
          setProgressSync(newProgress);
          isDragging = true;
        }
        break;
      case MotionEvent.ACTION_MOVE:
        if (isDragging) {
          //判断拖动时是否移出去了
          if (checkOnArc(currentX, currentY)) {
            setProgressSync(calDegreeByPosition(currentX, currentY) / ARC_FULL_DEGREE * max);
          } else {
            isDragging = false;
          }
        }
        break;
      case MotionEvent.ACTION_UP:
        isDragging = false;
        break;
    }
    return true;
  }
  private float calDistance(float x1, float y1, float x2, float y2) {
    return (float) Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
  }
  /**
   * 判断该点是否在弧线上(附近)
   */
  private boolean checkOnArc(float currentX, float currentY) {
    float distance = calDistance(currentX, currentY, centerX, centerY);
    float degree = calDegreeByPosition(currentX, currentY);
    return distance > circleRadius - STROKE_WIDTH * 5 && distance < circleRadius + STROKE_WIDTH * 5
        && (degree >= -8 && degree <= ARC_FULL_DEGREE + 8);
  }
  /**
   * 根据当前位置,计算出进度条已经转过的角度。
   */
  private float calDegreeByPosition(float currentX, float currentY) {
    float a1 = (float) (Math.atan(1.0f * (centerX - currentX) / (currentY - centerY)) / Math.PI * 180);
    if (currentY < centerY) {
      a1 += 180;
    } else if (currentY > centerY && currentX > centerX) {
      a1 += 360;
    }
    return a1 - (360 - ARC_FULL_DEGREE) / 2;
  }
  public void setMax(int max) {
    this.max = max;
    invalidate();
  }
  public void setProgress(float progress) {
    final float validProgress = checkProgress(progress);
    //动画切换进度值
    new Thread(new Runnable() {
      @Override
      public void run() {
        float oldProgress = ProgressBarView1.this.progress;
        for (int i = 1; i <= 100; i++) {
          ProgressBarView1.this.progress = oldProgress + (validProgress - oldProgress) * (1.0f * i / 100);
          postInvalidate();
          SystemClock.sleep(20);
        }
      }
    }).start();
  }
  public void setProgressSync(float progress) {
    this.progress = checkProgress(progress);
    invalidate();
  }
  //保证progress的值位于[0,max]
  private float checkProgress(float progress) {
    if (progress < 0) {
      return 0;
    }
    return progress > max ? max : progress;
  }
  public void setDraggingEnabled(boolean draggingEnabled) {
    this.draggingEnabled = draggingEnabled;
  }
}

(二)ProgressBarView2:

/**
 * 自定义绚丽的ProgressBar.
 */
public class ProgressBarView2 extends View {
  /**
   * 进度条所占用的角度
   */
  private static final int ARC_FULL_DEGREE = 300;
  //进度条个数
  private static final int COUNT = 100;
  //每个进度条所占用角度
  private static final float ARC_EACH_PROGRESS = ARC_FULL_DEGREE * 1.0f / (COUNT - 1);
  /**
   * 弧线细线条的长度
   */
  private int ARC_LINE_LENGTH;
  /**
   * 弧线细线条的宽度
   */
  private int ARC_LINE_WIDTH;
  /**
   * 组件的宽,高
   */
  private int width, height;
  /**
   * 进度条最大值和当前进度值
   */
  private float max, progress;
  /**
   * 绘制弧线的画笔
   */
  private Paint progressPaint;
  /**
   * 绘制文字的画笔
   */
  private Paint textPaint;
  /**
   * 绘制文字背景圆形的画笔
   */
  private Paint textBgPaint;
  /**
   * 圆弧的半径
   */
  private int circleRadius;
  /**
   * 圆弧圆心位置
   */
  private int centerX, centerY;
  public ProgressBarView2(Context context) {
    super(context);
    init();
  }
  public ProgressBarView2(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
  }
  public ProgressBarView2(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    init();
  }
  private void init() {
    progressPaint = new Paint();
    progressPaint.setAntiAlias(true);
    textPaint = new Paint();
    textPaint.setColor(Color.WHITE);
    textPaint.setAntiAlias(true);
    textBgPaint = new Paint();
    textBgPaint.setAntiAlias(true);
  }
  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    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;
    }
  }
  private Rect textBounds = new Rect();
  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    float start = (360 - ARC_FULL_DEGREE) >> 1; //进度条起始角度
    float sweep1 = ARC_FULL_DEGREE * (progress / max); //进度划过的角度
    //绘制进度条
    progressPaint.setColor(Color.parseColor(calColor(progress / max, "#ffff0000", "#ff00ff00")));
    progressPaint.setStrokeWidth(ARC_LINE_WIDTH);
    float drawDegree = 1.6f;
    while (drawDegree <= ARC_FULL_DEGREE) {
      double a = (start + drawDegree) / 180 * Math.PI;
      float lineStartX = centerX - circleRadius * (float) Math.sin(a);
      float lineStartY = centerY + circleRadius * (float) Math.cos(a);
      float lineStopX = lineStartX + ARC_LINE_LENGTH * (float) Math.sin(a);
      float lineStopY = 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) + "";
    float textLen = textPaint.measureText(text);
    //计算文字高度
    textPaint.getTextBounds("8", 0, 1, textBounds);
    float h1 = textBounds.height();
    canvas.drawText(text, centerX - textLen / 2, centerY - circleRadius / 10 + h1 / 2, textPaint);
    //分
    textPaint.setTextSize(circleRadius >> 3);
    textPaint.getTextBounds("分", 0, 1, textBounds);
    float h11 = 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);
  }
  public void setMax(int max) {
    this.max = max;
    invalidate();
  }
  //动画切换进度值(异步)
  public void setProgress(final float progress) {
    new Thread(new Runnable() {
      @Override
      public void run() {
        float oldProgress = ProgressBarView2.this.progress;
        for (int i = 1; i <= 100; i++) {
          ProgressBarView2.this.progress = oldProgress + (progress - oldProgress) * (1.0f * i / 100);
          postInvalidate();
          SystemClock.sleep(20);
        }
      }
    }).start();
  }
  //直接设置进度值(同步)
  public void setProgressSync(float progress) {
    this.progress = progress;
    invalidate();
  }
  /**
   * 计算渐变效果中间的某个颜色值。
   * 仅支持 #aarrggbb 模式,例如 #ccc9c9b2
   */
  public String calColor(float fraction, String startValue, String endValue) {
    int start_a, start_r, start_g, start_b;
    int end_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.
  private int getIntValue(String hexValue, int start, int end) {
    return Integer.parseInt(hexValue.substring(start, end), 16);
  }
  private String getHexString(int value) {
    String a = Integer.toHexString(value);
    if (a.length() == 1) {
      a = "0" + a;
    }
    return a;
  }
}

更多关于Android相关内容感兴趣的读者可查看本站专题:《Android视图View技巧总结》、《Android开发动画技巧汇总》、《Android编程之activity操作技巧总结》、《Android布局layout技巧总结》、《Android开发入门与进阶教程》、《Android资源操作技巧汇总》及《Android控件用法总结》

希望本文所述对大家Android程序设计有所帮助。




上一篇 : 新学年强身健体快 戴三星 Galaxy Watch6 系列开始锻炼

下一篇 : myisam存储引擎的特点是什么_mysql myisam存储引擎特性说明

推荐阅读

电话:400 76543 55
邮箱:915688610@qq.com
品牌营销
客服微信
搜索营销
公众号
©  丽景创新 版权所有 赣ICP备2024032158号 
宜昌市隼壹珍商贸有限公司 宜昌市隼壹珍商贸有限公司 宜昌市隼壹珍商贸有限公司 宜昌市隼壹珍商贸有限公司 宜昌市隼壹珍商贸有限公司 宜昌市隼壹珍商贸有限公司 宜昌市隼壹珍商贸有限公司 宜昌市隼壹珍商贸有限公司 宜昌市隼壹珍商贸有限公司 宜昌市隼壹珍商贸有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 内江振祥营销策划有限公司 恩施州毯滚百货有限公司 恩施州毯滚百货有限公司 襄阳市蜂欢商贸有限公司 襄阳市蜂欢商贸有限公司 恩施州换冯百货有限公司 恩施州换冯百货有限公司 恩施州健提百货有限公司 恩施州健提百货有限公司 西安益零商贸有限公司 西安益零商贸有限公司 南奥教育 南奥教育 南奥教育 南奥教育 南昌市南奥教育咨询有限公司 南昌市南奥教育咨询有限公司 南昌市南奥教育咨询有限公司 南昌市南奥教育咨询有限公司 南昌市南奥教育咨询有限公司 南昌市南奥教育咨询有限公司 南昌市南奥教育咨询有限公司 南昌市南奥教育咨询有限公司 南奥教育网 南奥教育网 南奥教育网 南奥教育网 南奥学习网 南奥学习网 南奥学习网 南奥学习网 南奥教育 南奥教育 南奥留学记 南奥留学记 南奥教育 南奥教育 南昌市南奥教育咨询有限公司 南昌市南奥教育咨询有限公司 南昌市南奥教育咨询有限公司 南昌市南奥教育咨询有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 南昌壹佳企网络通信有限公司 广照天下广告 广照天下广告 广照天下广告策划 广照天下广告策划 广照天下 广照天下 广照天下 广照天下 广照天下 广照天下 广照天下广告策划 广照天下广告策划 广照天下广告策划 广照天下广告策划 南昌市广照天下广告策划有限公司 南昌市广照天下广告策划有限公司 南昌市广照天下广告策划有限公司 南昌市广照天下广告策划有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 宿州市腾雀网络科技有限公司 九江市云仁商务咨询有限公司 九江市云仁商务咨询有限公司 九江市云仁商务咨询有限公司 九江市云仁商务咨询有限公司 九江市云仁商务咨询有限公司 九江市云仁商务咨询有限公司 九江市云仁商务咨询有限公司 九江市云仁商务咨询有限公司 九江市云仁商务咨询有限公司 九江市云仁商务咨询有限公司
品牌营销
专业SEO优化
添加左侧专家微信
获取产品详细报价方案