仿IWatch环形进度条自定义控件


  • 一、环形进度条
    • 1、自定义属性
    • 2、绘制
    • 3、实现动态刷新机制
    • 4、部署控件
  • 二、进度条嵌套集合
    • 1、自定义属性
    • 2、控件部署
  • 三、一键部署IWatch环形进度条自定义控件

环形进度条可以设置圆环宽度、圆环进度颜色、圆环轨道颜色、圆环刷新速率、文案内容等属性,可实现更多展示效果。并将进度条子集进行汇总嵌套,通过设置圆环间隔呈现IWatch环形进度条效果。

一、环形进度条

环形进度条.png

1、自定义属性

  • 在XML布局中可配置控件的属性,实现自定义控件时,我们需要抽出可配置的公有属性,方便塑造更多形式。

字段名 字段类型 字段说明
_roundColor color 进度条背景色
_roundProgressColor color 进度填充色
_roundWidth color 进度画笔宽
_textColor dimension 进度文字色
_rate integer 进度刷新速率
_max integer 进度最大值
_progress integer 进度值
_textIsDisplayable boolean 是否显示进度文字
_style enum 环形进度条是否镂空,STROKE,FILL

    
    
    
    
    
    
    
    
    
        
        
    

2、绘制

  • 需定义每个元素的画笔属性和绘制位置,相互之间可以形成约束,比如圆环宽可以和文字大小和圆点大小形成约束,降低用户操作难度。

  • 计算字体大小跟随进度宽度变化

int centerX = getWidth() / 2; // 获取圆心的x坐标
int centerY = getHeight() / 2;
int radius;
if (centerX > centerY) {
    radius = (int) (centerY - roundWidth); // 圆环的半径 减10的目的是为了让字体
} else {
    radius = (int) (centerX - roundWidth); // 圆环的半径 减10的目的是为了让字体
}
lessSize = 20;
textSize = roundWidth / 2 + 35;//根据画笔宽度改变字体大小        
  • 绘制底部圆轨道

paint.setColor(roundColor); // 设置圆环的颜色
paint.setStyle(Paint.Style.STROKE); // 设置空心
paint.setStrokeWidth(roundWidth); // 设置圆环的宽度
paint.setAntiAlias(true); // 消除锯齿
canvas.drawCircle(centerX, centerY, radius, paint); // 画出圆环
  • 绘制圆心文字

if (textIsDisplayable && style == STROKE){
  paint.setColor(Color.WHITE);
  paint.setTextSize(textSize);
  paint.setTypeface(Typeface.DEFAULT); // 设置字体

  float p = 0.0f;
  if (max != 0) {
      p = ((float) progress / (float) max) * 100.0f;
  }
  DecimalFormat decimalFormat = new DecimalFormat("######0.0");//构造方法的字符格式这里如果小数不足1位,会以0补足.
  String percent = decimalFormat.format(p) + "%";//format 返回的是字符串
  float percentWidth = paint.measureText(percent);// 测量字体宽度,我们需要根据字体的宽度设置在圆环中间
  canvas.drawText(percent, centerX - percentWidth / 2, centerY, paint); // 画出进度百分比

  paint.setTextSize(textSize); // 改变画笔字体大小格式
  String s = text + "率";
  float textWidth = paint.measureText(s); // 测量字体宽度,我们需要根据字体的宽度设置在圆环中间
  canvas.drawText(s, centerX - textWidth / 2, centerY + (textSize - lessSize / 2), paint); // 画出进度百分比
}
  • 绘制带圆角的圆弧进度

paint.setStrokeWidth(roundWidth); // 设置圆环的宽度
paint.setColor(roundProgressColor); // 设置进度的颜色
RectF oval = new RectF((centerX - radius), (centerY - radius),
                (centerX + radius), (centerY + radius)); // 用于定义的圆弧的形状和大小的界限

switch (style) {
  case STROKE: {
      paint.setStyle(Paint.Style.STROKE); // 设置进度是实心还是空心
      paint.setStrokeCap(Paint.Cap.ROUND); // 设置线冒样式
      if (max != 0) {
          if (progress == 0) {
              canvas.drawArc(oval, -90, 1, false, paint);
          } else {
              canvas.drawArc(oval, -90, (count) * 360 / max, false, paint); // 根据进度画圆弧
          }
      } else {
          canvas.drawArc(oval, 0, 0, false, paint); // 根据进度画圆弧
      }
      break;
  }
  case FILL: {
      paint.setStyle(Paint.Style.FILL_AND_STROKE);
      if (max != 0) {
          if (progress == 0) {
              canvas.drawArc(oval, -90, 1, true, paint);
          } else {
              canvas.drawArc(oval, -90, (count) * 360 / max, true, paint); // 根据进度画圆弧
          }
      } else {
          canvas.drawArc(oval, 0, 0, true, paint); // 根据进度画圆弧
      }
      break;
  }
}
  • 绘制与圆环顶部齐平的进度条文字描述和小圆点

// 绘制与圆环填充色一致的小圆点
paint.setColor(roundProgressColor);
paint.setStyle(Paint.Style.FILL);
paint.setStrokeWidth(roundWidth / 2);
canvas.drawCircle(centerX - 6 * distance, centerY - radius + distance / 2, distance / 3, paint);

// 绘制文字描述
paint.setColor(textColor);// 设置字体
paint.setTextSize(textSize); // 改变画笔字体大小格式
canvas.drawText(text + progress, centerX - 5 * distance,
                centerY + (textSize - lessSize) / 2 - radius, paint); // 画出进度百分比

3、实现动态刷新机制

  • 利用Handler的消息延时机制,按照一定速率的增加绘制进度,实现动态刷新效果

/**
 * 记录当前所画的每小块圆弧个数
 */
private int count = 0;

/**
 * 记录还没画出的圆弧进度
 */
private int reverse_pro;

/**
 * 圆环动画速度
 */
private int rate;

/**
 * 设置进度,此为线程安全控件,由于考虑多线的问题,需要同步 刷新界面调用postInvalidate()能在非UI线程刷新
 *
 * @param progress 当前需绘制的进度
 */
public synchronized void setProgress(int progress) {
    if (progress < 0) {
        throw new IllegalArgumentException("progress not less than 0");
    }
    if (progress > max) {
        progress = max;
    }
    if (progress <= max) {
        this.progress = progress;
        count = 0;
        reverse_pro = progress;// 将传进来的进程数传给用来记录当前圆环的比率
        postInvalidate();
    }
}
public void refreshProgress() {
    count = 0; // 记录已经绘制好的圆弧进度,在 onDraw 中运用
    reverse_pro = progress; // 记录还没画出的圆弧进度

    Message message = handler.obtainMessage(1);
    handler.sendMessageDelayed(message, rate);
}

Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case 1:
                if (reverse_pro != 0)
                    count++;
                reverse_pro--;
                postInvalidate();// progress每增加一格就刷新一次界面,用count来记录弧度单元格个数
                if (reverse_pro > 0) {
                    Message message = handler.obtainMessage(1);
                    handler.sendMessageDelayed(message, rate);
                }
                break;
        }
        super.handleMessage(msg);
    }
};

4、部署控件


二、进度条嵌套集合

环形进度条嵌套集合.png

1、自定义属性

字段名 字段类型 字段说明
rate integer 进度刷新速率
progressTrackColor color 进度条底部轨道颜色
textColor color 进度条文字颜色
progressGap dimension 每根进度条彼此间隔
roundWidth dimension 每根进度条绘制宽度
onlyFirstShowCenter boolean 总体是否只显示第一条进度的中心文案
isShowTopTextAndPoint boolean 每条进度是否显示顶部齐平的文案和圆点

    
    
    
    
    
    
    

public ProgressBarsView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    mContext = context;

    TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.ProgressBarsView);
    // 获取自定义属性和默认值
    progressTrackColor = mTypedArray.getColor(R.styleable.ProgressBarsView_progressTrackColor, Color.GRAY); // 每条进度底部轨道颜色一致
    textColor = mTypedArray.getColor(R.styleable.ProgressBarsView_textColor, Color.WHITE); // 每条进度文字颜色一致
    rate = mTypedArray.getInteger(R.styleable.ProgressBarsView_rate, 50); // 每条进度刷新速率一致
    progressGap = mTypedArray.getDimension(R.styleable.ProgressBarsView_progressGap, 10); // 每条进度彼此间隔一致
    roundWidth = mTypedArray.getDimension(R.styleable.ProgressBarsView_roundWidth, 20); // 每条进度宽度一致
    onlyFirstShowCenter = mTypedArray.getBoolean(R.styleable.ProgressBarsView_onlyFirstShowCenter, true); // 总体是否只显示第一条进度的中心文案
    isShowTopTextAndPoint = mTypedArray.getBoolean(R.styleable.ProgressBarsView_isShowTopTextAndPoint, true); // 每条进度是否显示顶部齐平的文案和圆点
}

2、控件部署


public void addProgressBar(String text, int progressColor, int maxProgress, int progress) {
    ViewHolder holder = new ViewHolder();
    holder.rate = rate;
    holder.roundWidth = roundWidth;
    holder.progressTrackColor = progressTrackColor;
    holder.isShowTopTextAndPoint = isShowTopTextAndPoint;
    holder.textColor = textColor;

    holder.max = maxProgress;
    holder.progress = progress;
    holder.text = text;
    holder.roundProgressColor = progressColor;
    list.add(holder);
}
public void showProgress() {
    this.removeAllViews();

    for (int i = 0; i < list.size(); i++) {
        ViewHolder holder = list.get(i);
        ChildProgressBar progressBar = new ChildProgressBar(mContext);
        progressBar.setText(holder.text);
        progressBar.setTextColor(holder.textColor);
        progressBar.setCricleColor(holder.progressTrackColor);
        progressBar.setCricleProgressColor(holder.roundProgressColor);
        progressBar.setRoundWidth(holder.roundWidth);
        progressBar.setRate(holder.rate);
        progressBar.setMax(holder.max);
        progressBar.setProgress(holder.progress);
        progressBar.setTextIsDisplayable(i == 0 && onlyFirstShowCenter); // 是否绘制圆中心文案
        progressBar.setShowTextHint(holder.isShowTopTextAndPoint); // 是否绘制与圆顶部平行的文字和圆点

        float totalMargin = (roundWidth + progressGap) * i;
        LayoutParams params = new LayoutParams(
                android.view.ViewGroup.LayoutParams.MATCH_PARENT,
                android.view.ViewGroup.LayoutParams.MATCH_PARENT);
        params.setMargins((int) totalMargin, (int) totalMargin,
                (int) totalMargin, (int) totalMargin);
        this.addView(progressBar, params);

        progressBar.updateBar();
    }
}

三、一键部署IWatch环形进度条自定义控件

progressbar.addProgressBar("胜", 0XBBEA595C, 100, 80);
progressbar.addProgressBar("平", 0XBBD6A20E, 100, 90);
progressbar.addProgressBar("负", 0XBBD7D5DA, 100, 30);
progressbar.showProgress();
仿IWatch环形进度条嵌套集合.png
IWatch环形进度条控件.jpg

你可能感兴趣的:(仿IWatch环形进度条自定义控件)