263 lines
8.3 KiB
Java
263 lines
8.3 KiB
Java
package com.arpa.mylibrary.weight;
|
||
|
||
import android.animation.ValueAnimator;
|
||
import android.content.Context;
|
||
import android.content.res.TypedArray;
|
||
import android.graphics.Canvas;
|
||
import android.graphics.Paint;
|
||
import android.graphics.Point;
|
||
import android.graphics.Rect;
|
||
import android.graphics.RectF;
|
||
import android.util.AttributeSet;
|
||
import android.view.View;
|
||
import android.view.animation.DecelerateInterpolator;
|
||
|
||
import com.arpa.mylibrary.R;
|
||
|
||
/**
|
||
* @ClassName CircleBarView2
|
||
* @Author john
|
||
* @Date 2024/2/7 16:28
|
||
* @Description TODO
|
||
*/
|
||
public class CircleBarView2 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 = getContext().getColor(R.color.color_f25);
|
||
// 设置数值颜色
|
||
private int valueColor = getContext().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 CircleBarView2(Context context) {
|
||
this(context, null);
|
||
}
|
||
|
||
public CircleBarView2(Context context, AttributeSet attrs) {
|
||
this(context, attrs, 0);
|
||
}
|
||
|
||
public CircleBarView2(Context context, AttributeSet attrs, int defStyleAttr) {
|
||
super(context, attrs, defStyleAttr);
|
||
initAttrs(context, attrs);
|
||
}
|
||
|
||
public int getMax() {
|
||
return max;
|
||
}
|
||
|
||
public void setMax(int max) {
|
||
this.max = max;
|
||
}
|
||
|
||
public int getProgress() {
|
||
return progress;
|
||
}
|
||
|
||
public void setProgress(int progress) {
|
||
if (progress != 0 && 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();
|
||
CircleBarView2.this.progress = (int) nowPro;
|
||
valueText = String.valueOf(CircleBarView2.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, AttributeSet attrs) {
|
||
|
||
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleBarView);
|
||
// 文字间距
|
||
textMargin = dp2px(context, 5);
|
||
// 圆弧宽度
|
||
roundWidth = dp2px(context, 8);
|
||
// 半径
|
||
radius = dp2px(context, 92);
|
||
height = radius;
|
||
// 小间距
|
||
smallMargin = roundWidth / 2;
|
||
|
||
outPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||
outPaint.setColor(context.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(context.getColor(R.color.color_f15));
|
||
innerPaint.setStyle(Paint.Style.STROKE);
|
||
innerPaint.setStrokeCap(Paint.Cap.ROUND);
|
||
innerPaint.setStrokeWidth(roundWidth + 10);
|
||
|
||
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||
mTextPaint.setColor(context.getColor(R.color.color_9));
|
||
mTextPaint.setTextSize(sp2px(getContext(), 16));
|
||
|
||
mValueTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||
mValueTextPaint.setColor(valueColor);
|
||
mValueTextPaint.setTextSize(sp2px(getContext(), 34));
|
||
|
||
mUnitTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||
mUnitTextPaint.setColor(context.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(getContext().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);
|
||
}
|
||
}
|