效果:
1.View
package com.example.myview;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
import android.view.animation.DecelerateInterpolator;
import androidx.annotation.Nullable;
public class StepView extends View {
int outerColor;
int innerColor;
float borderWidth;
int textColor;
int textSize;
String defaultOuterColor = "#123456";
String defaultInnerColor = "#FAB570";
String defaultTextColor = "#123456";
int defaultTextSize = 20;
int defaultBorderWidth = 2;
Paint outerPaint;//外圆弧
Paint innerPaint;//内圆弧
Paint textPaint;//文字
private int maxValue;//圆弧最大值
private int currentValue;//圆弧当前值
public StepView(Context context) {
super(context);
}
public StepView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public synchronized void setMaxValue(int maxValue, int finalValue, long time) {
this.maxValue = maxValue;
refresh(finalValue, time);
}
public synchronized void setCurrentValue(int currentValue) {
this.currentValue = currentValue;
invalidate();
}
private void refresh(int finalValue, long time) {
ValueAnimator valueAnimator = ObjectAnimator.ofFloat(0, finalValue);
valueAnimator.setDuration(time * 1000);
valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.addUpdateListener(animation -> {
float currentStep = (float) animation.getAnimatedValue();
setCurrentValue((int) currentStep);
});
valueAnimator.start();
}
public StepView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.StepView);
outerColor = array.getColor(R.styleable.StepView_outerColor, Color.parseColor(defaultOuterColor));
innerColor = array.getColor(R.styleable.StepView_innerColor, Color.parseColor(defaultInnerColor));
borderWidth = array.getDimensionPixelSize(R.styleable.StepView_borderWidth, defaultBorderWidth);
textColor = array.getColor(R.styleable.StepView_textColor, Color.parseColor(defaultTextColor));
textSize = array.getDimensionPixelSize(R.styleable.StepView_textSize, defaultTextSize);
array.recycle();
outerPaint = new Paint();
outerPaint.setColor(outerColor);
outerPaint.setStrokeWidth(borderWidth);
outerPaint.setAntiAlias(true);//抗锯齿
outerPaint.setStrokeCap(Paint.Cap.ROUND);//给圆弧戴个帽子
outerPaint.setStyle(Paint.Style.STROKE);//空心
innerPaint = new Paint();
innerPaint.setColor(innerColor);
innerPaint.setStrokeWidth(borderWidth);
innerPaint.setAntiAlias(true);
innerPaint.setStrokeCap(Paint.Cap.ROUND);
innerPaint.setStyle(Paint.Style.STROKE);
textPaint = new Paint();
textPaint.setColor(textColor);
textPaint.setTextSize(textSize);
textPaint.setAntiAlias(true);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//宽高不一致时取最小值
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width > height ? height : width, width > height ? height : width);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//外圆弧
RectF rect = new RectF(borderWidth / 2, borderWidth / 2, getWidth() - borderWidth / 2, getWidth() - borderWidth / 2);
canvas.drawArc(rect, 135, 270, false, outerPaint);
//内圆弧 百分比
if (maxValue == 0)
return;
float percentage = (float) currentValue / (float) maxValue;
RectF rect2 = new RectF(borderWidth / 2, borderWidth / 2, getWidth() - borderWidth / 2, getWidth() - borderWidth / 2);
canvas.drawArc(rect2, 135, 270 * percentage, false, innerPaint);
//文字
Paint.FontMetrics metrics = textPaint.getFontMetrics();
float baseline = (getHeight() - metrics.bottom - metrics.top) / 2;
String stepText = currentValue + "";
Rect textBounds = new Rect();
textPaint.getTextBounds(stepText, 0, stepText.length(), textBounds);
int dx = getWidth() / 2 - textBounds.width() / 2;
canvas.drawText(stepText, dx, baseline, textPaint);
}
}
2.使用
<com.example.myview.StepView
android:id="@+id/stepView"
app:borderWidth="20dp"
android:layout_centerInParent="true"
app:textSize="30sp"
android:layout_width="400dp"
android:layout_height="400dp" />
stepView.setMaxValue(4000,3000,4);
补充个效果,加文字的,如下图,位置可以根据自己的需要自行调整
修改代码
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//外圆弧
RectF rect = new RectF(borderWidth / 2, borderWidth / 2, getWidth() - borderWidth / 2, getWidth() - borderWidth / 2);
canvas.drawArc(rect, 135, 270, false, outerPaint);
//内圆弧 百分比
if (maxValue == 0)
return;
float percentage = (float) currentValue / (float) maxValue;
RectF rect2 = new RectF(borderWidth / 2, borderWidth / 2, getWidth() - borderWidth / 2, getWidth() - borderWidth / 2);
canvas.drawArc(rect2, 135, 270 * percentage, false, innerPaint);
//文字
Paint.FontMetrics metrics = textPaint.getFontMetrics();
float baseline = (getHeight() - metrics.bottom - metrics.top) / 2;
String stepText = "今日步数";
Rect textBounds = new Rect();
textPaint.getTextBounds(stepText, 0, stepText.length(), textBounds);
int dx = getWidth() / 2 - textBounds.width() / 2;
canvas.drawText(stepText, dx, baseline - textBounds.height()*2 , textPaint);
//步数
String stepText2 = ""+currentValue;
Rect textBounds2 = new Rect();
textPaint.getTextBounds(stepText2, 0, stepText2.length(), textBounds2);
int dx2 = getWidth() / 2 - textBounds2.width() / 2;
canvas.drawText(stepText2, dx2, baseline -textBounds2.height()/2 , textPaint);
}