车队管理完善
This commit is contained in:
@@ -0,0 +1,323 @@
|
||||
package com.dahe.mylibrary.weight;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.LinearGradient;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.SweepGradient;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.Transformation;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.dahe.mylibrary.R;
|
||||
|
||||
/**
|
||||
* @ClassName CircleBarView
|
||||
* @Author john
|
||||
* @Date 2024/2/7 16:08
|
||||
* @Description TODO
|
||||
*/
|
||||
public class CircleBarView extends View {
|
||||
private Paint rPaint;//绘制矩形的画笔
|
||||
private Paint progressPaint;//绘制圆弧的画笔
|
||||
private Paint anchorPaint, anchorBgPaint;//锚点
|
||||
private float anchorRadius, anchorBgRadius;
|
||||
private int anchorColor, anchorBgColor;
|
||||
private CircleBarAnim anim;
|
||||
private Paint bgPaint;//绘制背景圆弧的画笔
|
||||
private float progress;//可以更新的进度条数值
|
||||
private float maxProgress;//进度条最大值
|
||||
private float progressSweepAngle;//进度条圆弧扫过的角度
|
||||
private int startAngle;//背景圆弧的起始角度
|
||||
private float sweepAngle;//背景圆弧扫过的角度
|
||||
private RectF mRectF;//绘制圆弧的矩形区域
|
||||
private float barWidth;//圆弧进度条宽度
|
||||
private int defaultSize;//自定义View默认的宽高
|
||||
private int[] progressColors;//进度条圆弧颜色
|
||||
private int bgColor;//背景圆弧颜色
|
||||
private SweepGradient sweepGradient;//进度条颜色使用渐变色
|
||||
private LinearGradient linearGradient;
|
||||
private float circleWidth, circleHeight;
|
||||
private float xDiff;
|
||||
|
||||
public CircleBarView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
init(context, attrs);
|
||||
}
|
||||
|
||||
private void init(Context context, AttributeSet attrs) {
|
||||
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleBarView);
|
||||
int color1 = typedArray.getColor(R.styleable.CircleBarView_progress_color1, Color.RED);
|
||||
int color2 = typedArray.getColor(R.styleable.CircleBarView_progress_color2, color1);
|
||||
int color3 = typedArray.getColor(R.styleable.CircleBarView_progress_color3, color2);//写法巧妙
|
||||
progressColors = new int[]{color1, color1, color2, color3};//必须得4个,
|
||||
bgColor = typedArray.getColor(R.styleable.CircleBarView_bg_color, Color.GRAY);//默认为灰色
|
||||
circleWidth = typedArray.getDimension(R.styleable.CircleBarView_circle_width, dip2px(context, 200));//默认为0
|
||||
circleHeight = typedArray.getDimension(R.styleable.CircleBarView_circle_height, dip2px(context, 80));//默认为360
|
||||
barWidth = typedArray.getDimension(R.styleable.CircleBarView_bar_width, dip2px(context, 10));//默认为10dp
|
||||
anchorRadius = typedArray.getDimension(R.styleable.CircleBarView_anchor_radius, dip2px(context, 5));
|
||||
anchorBgRadius = typedArray.getDimension(R.styleable.CircleBarView_anchor_bg_radius, dip2px(context, 8.5f));
|
||||
anchorColor = typedArray.getColor(R.styleable.CircleBarView_anchor_color, Color.RED);
|
||||
anchorBgColor = typedArray.getColor(R.styleable.CircleBarView_anchor_bg_color, Color.GREEN);
|
||||
maxProgress = typedArray.getInt(R.styleable.CircleBarView_progress_max, 100);
|
||||
typedArray.recycle();//typedArray用完之后需要回收,防止内存泄漏
|
||||
|
||||
rPaint = new Paint();
|
||||
rPaint.setStyle(Paint.Style.STROKE);//只描边,不填充
|
||||
rPaint.setColor(Color.RED);
|
||||
|
||||
progressPaint = new Paint();
|
||||
progressPaint.setStyle(Paint.Style.STROKE);//只描边,不填充
|
||||
|
||||
progressPaint.setStrokeWidth(barWidth);
|
||||
progressPaint.setAntiAlias(true);//设置抗锯齿
|
||||
progressPaint.setStrokeCap(Paint.Cap.ROUND);
|
||||
|
||||
//锚点
|
||||
anchorPaint = new Paint();
|
||||
anchorPaint.setAntiAlias(true);//设置抗锯齿
|
||||
anchorPaint.setColor(anchorColor);
|
||||
//锚点背景
|
||||
anchorBgPaint = new Paint();
|
||||
anchorBgPaint.setAntiAlias(true);//设置抗锯齿
|
||||
|
||||
int a = Color.alpha(anchorBgColor);
|
||||
int r = Color.red(anchorBgColor);
|
||||
int g = Color.green(anchorBgColor);
|
||||
int b = Color.blue(anchorBgColor);
|
||||
// LogSuperUtil.i("circle_bar", "a=" + a + ",r=" + r + ",g=" + g + ",b=" + b);
|
||||
anchorBgPaint.setColor(Color.rgb(r, g, b));
|
||||
anchorBgPaint.setAlpha(a);
|
||||
/*raw
|
||||
anchorBgPaint.setColor(anchorBgColor);
|
||||
anchorBgPaint.setAlpha(185);*/
|
||||
|
||||
anim = new CircleBarAnim();
|
||||
bgPaint = new Paint();
|
||||
bgPaint.setStyle(Paint.Style.STROKE);
|
||||
bgPaint.setColor(bgColor);
|
||||
bgPaint.setStrokeWidth(barWidth);
|
||||
bgPaint.setAntiAlias(true);
|
||||
bgPaint.setStrokeCap(Paint.Cap.ROUND);
|
||||
mRectF = new RectF();
|
||||
|
||||
//
|
||||
defaultSize = dip2px(context, 200);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
//进度条的总轮廓
|
||||
canvas.drawArc(mRectF, startAngle, sweepAngle, false, bgPaint);
|
||||
float outCircleRadius = mRectF.width() / 2;//带宽度的进度条的中线半径
|
||||
|
||||
if (sweepGradient == null) {
|
||||
float centerX = (mRectF.left + mRectF.right) / 2;
|
||||
float centerY = (mRectF.top + mRectF.bottom) / 2;
|
||||
//
|
||||
int rotateDiff = 30;//为了解决圆弧开头出的圆角颜色不正常的问题,30度够用了吧
|
||||
int rotateDegree = startAngle - rotateDiff;
|
||||
float sweepEndPosition = (rotateDiff + sweepAngle * progress / maxProgress * 1.0f) / 360;
|
||||
// LogSuperUtil.i("circle_bar", "startAngle=" + startAngle + ",sweepEndPosition=" + sweepEndPosition);
|
||||
|
||||
float[] positions = {0, rotateDiff * 1.0f / 360, sweepEndPosition, 1};
|
||||
sweepGradient = new SweepGradient(centerX, centerY, progressColors, positions);
|
||||
Matrix rotateMatrix = new Matrix();
|
||||
//设置渐变色
|
||||
rotateMatrix.setRotate(rotateDegree, centerX, centerY);//180表示从左侧开始往上渐变
|
||||
sweepGradient.setLocalMatrix(rotateMatrix);//sweepGradient默认是从0度方向开始渐变的,所以要逆转一下。
|
||||
progressPaint.setShader(sweepGradient);
|
||||
}
|
||||
/*
|
||||
if(linearGradient==null) {
|
||||
linearGradient = new LinearGradient(0, 0, outCircleRadius*2, 0, progressColors,
|
||||
null, LinearGradient.TileMode.CLAMP);
|
||||
progressPaint.setShader(linearGradient);
|
||||
}*/
|
||||
//进度条
|
||||
canvas.drawArc(mRectF, startAngle, progressSweepAngle, false, progressPaint);
|
||||
float anchorAngle = progressSweepAngle + (startAngle - 180);
|
||||
|
||||
float anchorCoordRedius = outCircleRadius - barWidth / 2;
|
||||
double cosValue = Math.cos(Math.toRadians(anchorAngle));
|
||||
double sinValue = Math.sin(Math.toRadians(anchorAngle));
|
||||
|
||||
float diffByAnchor = anchorBgRadius - barWidth / 2;//x和y的偏移正好都是这个
|
||||
//float cx=(float)(outCircleRadius-cosValue*anchorCoordRedius+diffByAnchor);
|
||||
float cx = (float) (outCircleRadius - cosValue * outCircleRadius + anchorBgRadius);
|
||||
//float cy=(float)(outCircleRadius-sinValue*anchorCoordRedius+diffByAnchor);
|
||||
float cy = (float) (outCircleRadius - sinValue * outCircleRadius + anchorBgRadius);
|
||||
canvas.drawCircle(cx - xDiff, cy, anchorRadius, anchorPaint);//锚点小圆
|
||||
canvas.drawCircle(cx - xDiff, cy, anchorBgRadius, anchorBgPaint);//锚点背景大圆
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
//int height=measureSize(defaultSize,heightMeasureSpec);
|
||||
//int width=measureSize(defaultSize,widthMeasureSpec);
|
||||
//startAngle是计算出来的,因为弦的这种,没法通过观察直接得出圆弧的起始角度
|
||||
//通过数学计算得知x
|
||||
//x是圆心(圆弧所在的圆的圆心)到弦(也就是圆弧的底部)的垂直距离
|
||||
float x = (circleWidth * circleWidth - 4 * circleHeight * circleHeight) / (8 * circleHeight);
|
||||
//画圆弧用到的圆的半径
|
||||
float r = x + circleHeight;
|
||||
//int r=(int)(circleWidth/2/Math.cos(Math.toRadians(startAngle-180)));
|
||||
//弦长/2/半径=cos(startAngle-180)
|
||||
//(startAngle-180)
|
||||
double asin = Math.asin(circleWidth / 2 / r);
|
||||
//LogSuperUtil.i("circle_bar","asin="+asin);
|
||||
int a = (int) Math.toDegrees(asin);
|
||||
//LogSuperUtil.i("circle_bar","a="+a);
|
||||
startAngle = 180 + (90 - a);
|
||||
sweepAngle = 2 * a;
|
||||
//int min=Math.max(width,height);//获取View最短边的长度
|
||||
int width = (int) (Math.sqrt(Math.pow(r + anchorBgRadius, 2) - Math.pow(x, 2)) * 2 + 0.5f + anchorBgRadius);//圆弧的宽度
|
||||
width = (int) (2 * (circleWidth / 2 + anchorBgRadius) + 0.5f);
|
||||
int height = (int) (circleHeight + anchorBgRadius + 0.5f + anchorBgRadius);
|
||||
//height=width;
|
||||
xDiff = r - circleWidth / 2;//画布是从最左边开始画圆且显示的,不偏移的话,显示的效果不对。
|
||||
// LogSuperUtil.i("circle_bar", "xDiff=" + xDiff);
|
||||
setMeasuredDimension(width, height);
|
||||
if (Math.min(width, height) >= barWidth * 2) {//这里简单限制了圆弧的最大宽度
|
||||
//1.mRectF决定着圆画在哪个框框里面
|
||||
//2.mRectF在当前View中,但不是完全占据当前View
|
||||
//3.弧度的粗细画的时候是均分到圆半径线的两侧的
|
||||
//4.之所以矩形设置的四个点有偏移,是因为有弧度宽度。
|
||||
//因为锚点也有宽度,点再次做调整.
|
||||
//mRectF.set(barWidth/2,barWidth/2,min-barWidth/2,min-barWidth/2);
|
||||
float diffByAnchor = anchorBgRadius - barWidth / 2;//受锚点影响需要修正的偏移
|
||||
//是整个圆的矩形,不是弧形区域所在的矩形
|
||||
mRectF.set(barWidth / 2 + diffByAnchor - xDiff, barWidth / 2 + diffByAnchor, barWidth / 2 + diffByAnchor + 2 * r - xDiff, barWidth / 2 + diffByAnchor + 2 * r);
|
||||
}
|
||||
}
|
||||
|
||||
private int measureSize(int defaultSize, int measureSpec) {
|
||||
int result = defaultSize;
|
||||
int specMode = MeasureSpec.getMode(measureSpec);
|
||||
int specSize = MeasureSpec.getSize(measureSpec);
|
||||
if (specMode == MeasureSpec.EXACTLY) {
|
||||
// LogSuperUtil.i("circle_bar", "=EXACTLY");
|
||||
result = specSize;
|
||||
} else if (specMode == MeasureSpec.AT_MOST) {
|
||||
// LogSuperUtil.i("circle_bar", "=AT_MOST");
|
||||
result = Math.min(result, specSize);
|
||||
} else {
|
||||
// LogSuperUtil.i("circle_bar", "=defaultSize");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private TextView textView;
|
||||
private OnAnimationListener onAnimationListener;
|
||||
|
||||
public class CircleBarAnim extends Animation {
|
||||
public CircleBarAnim() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyTransformation(float interpolatedTime, Transformation t) {
|
||||
super.applyTransformation(interpolatedTime, t);
|
||||
progressSweepAngle = interpolatedTime * sweepAngle * progress / maxProgress;//这里计算进度条的比例
|
||||
postInvalidate();
|
||||
if (textView != null && onAnimationListener != null) {
|
||||
textView.setText(onAnimationListener.howToChangeText(interpolatedTime, progress, maxProgress));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置显示文字的TextView
|
||||
*
|
||||
* @param textView
|
||||
*/
|
||||
public void setTextView(TextView textView) {
|
||||
this.textView = textView;
|
||||
}
|
||||
/*
|
||||
* circleBarView.setOnAnimationListener(new CircleBarView.OnAnimationListener() {
|
||||
@Override
|
||||
public String howToChangeText(float interpolatedTime, float progressNum, float maxNum) {
|
||||
DecimalFormat decimalFormat=new DecimalFormat("0.00");
|
||||
String s = decimalFormat.format(interpolatedTime * progressNum / maxNum * 100) + "%";
|
||||
return s;
|
||||
}
|
||||
});*/
|
||||
|
||||
|
||||
public interface OnAnimationListener {
|
||||
/**
|
||||
* 如何处理要显示的文字内容
|
||||
*
|
||||
* @param interpolatedTime 从0渐变成1,到1时结束动画
|
||||
* @param progressNum 进度条数值
|
||||
* @param maxNum 进度条最大值
|
||||
* @return
|
||||
*/
|
||||
String howToChangeText(float interpolatedTime, float progressNum, float maxNum);
|
||||
}
|
||||
|
||||
//写个方法给外部调用,用来设置动画时间
|
||||
public void setProgress(float progress, int time) {
|
||||
anim.setDuration(time);
|
||||
this.startAnimation(anim);
|
||||
this.progress = progress;
|
||||
}
|
||||
|
||||
public static int dip2px(Context context, float dpValue) {
|
||||
float scale = context.getResources().getDisplayMetrics().density;
|
||||
return (int) (dpValue * scale + 0.5f);
|
||||
}
|
||||
|
||||
public static int px2dip(Context context, float pxValue) {
|
||||
float scale = context.getResources().getDisplayMetrics().density;
|
||||
return (int) (pxValue / scale + 0.5f);
|
||||
}
|
||||
|
||||
/**
|
||||
* //extraDistance比较小时,TextView离圆弧很近,是正常,因为TextView是从其自身的左上角开始渲染。
|
||||
*
|
||||
* @param sweepAnglePercent
|
||||
* @param extraDistance
|
||||
* @return
|
||||
*/
|
||||
public float getAngleX(float sweepAnglePercent, int extraDistance) {
|
||||
float outCircleRadius = mRectF.width() / 2 + barWidth / 2;//带宽度的进度条的外圆半径
|
||||
float diffByAnchor = anchorBgRadius - barWidth / 2;//x和y的偏移正好都是这个
|
||||
float x = (float) (outCircleRadius + diffByAnchor - Math.cos(Math.toRadians(startAngle - 180 + sweepAnglePercent * sweepAngle)) * (outCircleRadius + dip2px(getContext(), extraDistance)) - xDiff);
|
||||
return x;
|
||||
}
|
||||
|
||||
private static final String TAG = "circle_bar";
|
||||
|
||||
/**
|
||||
* 在当前View中的y坐标
|
||||
* (注意,TextView渲染的时候,这个坐标是作为TextView控件的左上角进行渲染。
|
||||
* 所以,extraDistance小的话,显示的结果TextView可能还在当前View的内部呢,但TextView的左上角是在圆外部的。
|
||||
*
|
||||
* @param sweepAnglePercent
|
||||
* @param extraDistance 从外圆算的往外扩展的距离,不是从锚点背景边缘往外扩展。
|
||||
* @return
|
||||
*/
|
||||
public float getAngleY(float sweepAnglePercent, int extraDistance) {
|
||||
float outCircleRadius = mRectF.width() / 2 + barWidth / 2;//带宽度的进度条的外圆半径
|
||||
float diffByAnchor = anchorBgRadius - barWidth / 2;//x和y的偏移正好都是这个
|
||||
float coordA = startAngle - 180 + sweepAnglePercent * sweepAngle;
|
||||
// LogSuperUtil.i("circle_bar", "coordA=" + coordA);
|
||||
float coordY = (float) Math.sin(Math.toRadians(coordA)) * (outCircleRadius + dip2px(getContext(), extraDistance));
|
||||
// LogSuperUtil.i("circle_bar", "coordY=" + coordY);
|
||||
float tempR = outCircleRadius + diffByAnchor;
|
||||
// LogSuperUtil.i("circle_bar", "tempR=" + tempR + ",=" + circleWidth);//CircleWidth是圆弧宽度
|
||||
// LogSuperUtil.i("circle_bar", "mRectF.width()/2=" + mRectF.width() / 2);
|
||||
float y = (float) (tempR - coordY);
|
||||
return y;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
package com.dahe.mylibrary.weight;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
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.dahe.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);
|
||||
}
|
||||
|
||||
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();
|
||||
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) {
|
||||
// 文字间距
|
||||
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(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);
|
||||
|
||||
mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mTextPaint.setColor(context.getColor(R.color.color_ff3));
|
||||
mTextPaint.setTextSize(sp2px(getContext(), 24));
|
||||
|
||||
mValueTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
|
||||
mValueTextPaint.setColor(valueColor);
|
||||
mValueTextPaint.setTextSize(sp2px(getContext(), 24));
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -29,5 +29,10 @@
|
||||
|
||||
|
||||
|
||||
<color name="color_f6">#F6F6F6</color>
|
||||
<color name="color_f15">#F15F15</color>
|
||||
<color name="color_ff3">#FF3FF3</color>
|
||||
<color name="color_f25">#f25f25</color>
|
||||
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -52,4 +52,28 @@
|
||||
<item name="android:windowIsFloating">true</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
</style>
|
||||
|
||||
|
||||
<declare-styleable name="CircleBarView">
|
||||
<attr name="progress_color1" format="reference|color"></attr>
|
||||
<attr name="progress_color2" format="reference|color"></attr>
|
||||
<attr name="progress_color3" format="reference|color"></attr>
|
||||
<attr name="bg_color" format="color"></attr>
|
||||
<attr name="bar_width" format="dimension"></attr>
|
||||
<attr name="circle_width" format="dimension"></attr><!--背景圆弧宽度 -->
|
||||
<attr name="circle_height" format="dimension"></attr><!--背景圆弧高度 -->
|
||||
<attr name="anchor_radius" format="dimension"></attr>
|
||||
<attr name="anchor_bg_radius" format="dimension"></attr>
|
||||
<attr name="anchor_color" format="reference|color"></attr>
|
||||
<attr name="anchor_bg_color" format="reference|color"></attr>
|
||||
<attr name="progress_max" format="integer"></attr>
|
||||
</declare-styleable>
|
||||
<declare-styleable name="CircleTextView">
|
||||
<attr name="paddingRing2Bg" format="dimension"></attr>
|
||||
<attr name="ringStrokeWidth" format="dimension"></attr>
|
||||
<attr name="ringColor1" format="reference|color"></attr>
|
||||
<attr name="ringColor2" format="reference|color"></attr>
|
||||
<attr name="bgColor1" format="reference|color"></attr>
|
||||
<attr name="bgColor2" format="reference|color"></attr>
|
||||
</declare-styleable>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user