Android-自定义半圆弧进度

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


1690510366196.jpg

下面是代码块
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);
}

}
使用方法:
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);

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容