Android-自定义半圆弧进度

140 阅读2分钟

项目中有一个自定义的半圆弧进度,并设置了类型和分数,记录一下,效果图如下:

下面是代码块

public class CircleBarView extends View {   
 private Paint outPaint, innerPaint;   
 private Paint mTextPaint, mValueTextPaint, mUnitTextPaint;   
 private final RectF oval = new RectF();    
//最大进度   
 private int max = 100;    
//当前进度    
private int progress = 0;    
//文本内容   
 private String text = "";    
//数值内容   
 private String valueText = "";   
 //单位内容   
 private String unitText = "";   
 // 圆弧颜色    
private int roundColor = ResourceUtil.getColor(R.color.color_f25);  
  // 设置数值颜色    
private int valueColor = ResourceUtil.getColor(R.color.color_f25);   
 //用于动画   
 private float nowPro = 0;   
 private ValueAnimator animator;  
  // 文字间距   
 private int textMargin;   
 // 圆弧宽度、半径和数值、小间距   
 private int roundWidth, radius, smallMargin;   
 // view的高度    
private int height;    
// 中心点    
private final Point centerPoint = new Point();   
 // 测量文字的范围   
 private final Rect textRect = new Rect();  
  public CircleBarView(Context context) {      
 this(context, null);   
 }   
 public CircleBarView(Context context, AttributeSet attrs) {  
      this(context, attrs, 0);  
  }  
  public CircleBarView(Context context, AttributeSet attrs, int defStyleAttr) {    
    super(context, attrs, defStyleAttr);   
     initAttrs(context); 
   }   
 public int getMax() {   
     return max;   
 }    
public void setMax(int max) {    
    this.max = max;  
  }   
 public int getProgress() {   
     return progress; 
   }   
 public void setProgress(int progress) { 
       if (this.progress == progress) {     
       return;     
   }       
 if (animator != null && animator.isRunning()) {  
          animator.cancel();       
 }     
   animator = ValueAnimator.ofFloat(nowPro, progress); 
       animator.setDuration(1000);      
  animator.setInterpolator(new DecelerateInterpolator());     
   animator.addUpdateListener(animation -> {        
    nowPro = (float) animation.getAnimatedValue();        
    CircleBarView.this.progress = (int) nowPro;       
     valueText = String.valueOf(CircleBarView.this.progress);     
       invalidate();     
   });       
 animator.start();   
 }    
public String getText() {   
     return text; 
   }   
 public void setText(String text) {     
   this.text = text;   
 }   
 public String getValueText() {       
 return valueText;  
  }   
 public void setValueText(String valueText) {   
     this.valueText = valueText; 
   }   
 public String getUnitText() {   
     return unitText;   
 }   
 public void setUnitText(String unitText) { 
       this.unitText = unitText;  
  }   
 public void setRoundColor(int roundColor) {   
     this.roundColor = roundColor;    
    invalidate();   
 }  
  public void setValueColor(int valueColor) { 
       this.valueColor = valueColor;    
    invalidate();   
 }    
private void initAttrs(Context context) {     
   // 文字间距       
 textMargin = dp2px(context, 5);     
   // 圆弧宽度       
 roundWidth = dp2px(context, 5);     
   // 半径       
 radius = dp2px(context, 72);   
     height = radius;       
 // 小间距     
   smallMargin = roundWidth / 2;    
    outPaint = new Paint(Paint.ANTI_ALIAS_FLAG);     
   outPaint.setColor(ResourceUtil.getColor(R.color.color_f6));      
  outPaint.setStyle(Paint.Style.STROKE);     
   outPaint.setStrokeCap(Paint.Cap.ROUND);   
     outPaint.setStrokeWidth(roundWidth);   
     innerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);    
    innerPaint.setColor(ResourceUtil.getColor(R.color.color_f15));  
      innerPaint.setStyle(Paint.Style.STROKE);    
    innerPaint.setStrokeCap(Paint.Cap.ROUND);   
     innerPaint.setStrokeWidth(roundWidth);      
  mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);  
      mTextPaint.setColor(ResourceUtil.getColor(R.color.color_ff3));     
   mTextPaint.setTextSize(sp2px(getContext(), 12));      
  mValueTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);    
    mValueTextPaint.setColor(valueColor);   
     mValueTextPaint.setTextSize(sp2px(getContext(), 24));   
     mUnitTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);     
   mUnitTextPaint.setColor(ResourceUtil.getColor(R.color.color_ff3));   
     mUnitTextPaint.setTextSize(sp2px(getContext(), 12));      
  //动画       
 animator = ValueAnimator.ofFloat(0, progress);   
     animator.setDuration(1000);    
    animator.setInterpolator(new DecelerateInterpolator());   
     animator.addUpdateListener(animation -> {     
       nowPro = (float) animation.getAnimatedValue();       
     postInvalidate();       
 });       
 animator.start();  
  }  
  @Override   
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
      super.onMeasure(widthMeasureSpec, heightMeasureSpec);     
   int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);     
   int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);   
     int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);   
     int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);   
     if (widthSpecMode == MeasureSpec.AT_MOST && heightSpecMode == MeasureSpec.AT_MOST) {  
          setMeasuredDimension(widthSpecSize, (int) height);      
  } else if (widthSpecMode == MeasureSpec.AT_MOST) {     
       setMeasuredDimension(widthSpecSize, heightSpecSize);        
    height = heightSpecSize;     
   } else if (heightSpecMode == MeasureSpec.AT_MOST) {    
        setMeasuredDimension(widthSpecSize, (int) height);     
   }    
}    

@Override   
 protected void onSizeChanged(int w, int h, int oldw, int oldh) {   
     super.onSizeChanged(w, h, oldw, oldh);   
     // 中心点      
  centerPoint.set(getWidth() / 2, height / 2);    
    // 计算圆弧显示的范围,height * 2 是因为圆弧的高度是根据园来算的,所以双倍才是半个圆    
    oval.set(getWidth() / 2f - radius, (float) roundWidth, getWidth() / 2f + radius, height * 2 - roundWidth*2);    }   

 @Override    protected void onDraw(Canvas canvas) {      
  // 最外层圆弧       
 canvas.drawArc(oval, 180, 180, false, outPaint);
 //绘制外层圆弧      
  // 进度圆弧      
  if (nowPro > 0) {       
     innerPaint.setColor(roundColor);   
     } else {          
  innerPaint.setColor(ResourceUtil.getColor(R.color.color_f6));      
  }       
 canvas.drawArc(oval, 180, 180f * nowPro / max, false, innerPaint);
 //绘制圆弧       
 // 文字从底部从下往上绘制。      
  int valueY = height - smallMargin;     
   // 值        
float valueTextWidth = mValueTextPaint.measureText(valueText);    
    float unitTextWidth = mUnitTextPaint.measureText(unitText);       
 canvas.drawText(valueText, centerPoint.x - (valueTextWidth + unitTextWidth) / 2f, valueY, mValueTextPaint);       
 // 单位       
 canvas.drawText(unitText, centerPoint.x + valueTextWidth / 2f - unitTextWidth / 2f + smallMargin, valueY, mUnitTextPaint);     
   // 测量值的高度       
 mValueTextPaint.getTextBounds(text, 0, text.length(), textRect);      
  // 提示文字("高血压")       
 float textWidth = mTextPaint.measureText(text);     
   // 文字的高度 = 值的高度起点 - 值的高度 - 间距      
  float textY = valueY - textRect.height() - textMargin;     
   canvas.drawText(text, centerPoint.x - textWidth / 2f, textY, mTextPaint);    
}   
 /**     * dp 转 px     */   
 private int dp2px(Context context, float dpValue) {      
  final float scale = context.getResources().getDisplayMetrics().density;    
    return (int) (dpValue * scale + 0.5f);   
 }  
  /**     * sp 转 px     */    
private int sp2px(Context context, float spValue) {   
     final float scale = context.getResources().getDisplayMetrics().scaledDensity;  
      return (int) (spValue * scale + 0.5f);   
 }
}



代码中的ResourceUtil 直接换成getResource()的形式也可以。


使用方法:
xml中
<xxx.xxx.CircleBarView    
android:id="@+id/circle_bar_view"    
android:layout_width="match_parent"   
 android:layout_height="80dp"/>

activity中 :
circleBarView.setText("高风险");
circleBarView.setValueText("0");
circleBarView.setUnitText("分");
circleBarView.setProgress(100);