1.在res下的values下面新建attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="QView">
<attr name="outerColor" format="color"/>
<attr name="innerColor" format="color"/>
<attr name="borderWidth" format="dimension"/>
<attr name="stepTextSize" format="dimension"/>
<attr name="stepTextColor" format="color"/>
</declare-styleable>
</resources>
2.创建自定义的view
package com.example.view;
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.util.TypedValue;
import android.view.View;
import androidx.annotation.Nullable;
public class QView extends View {
private int mOuterColor = Color.parseColor("#2196F3");
private int mInnerColor = Color.parseColor("#F44336");
private int mBorderWidth = 20; // PX
private int mStepTextSize = 18; //PX
private int mStepTextColor = Color.parseColor("#EC407A");
private int mSeptMax = 10000; // 总共的步数
private int mSeptCurrent = 1000; // 当前步数
private Paint mOutPaint;
private Paint mInnerPaint;
private Paint mTextPaint;
public QView(Context context) {
this(context, null);
}
public QView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public QView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.QView);
mOuterColor = array.getColor(R.styleable.QView_outerColor, mOuterColor);
mInnerColor = array.getColor(R.styleable.QView_innerColor, mInnerColor);
mBorderWidth = (int) array.getDimension(R.styleable.QView_borderWidth, mBorderWidth);
mStepTextSize = array.getDimensionPixelSize(R.styleable.QView_stepTextSize, mStepTextSize);
mStepTextColor = array.getColor(R.styleable.QView_stepTextColor, mStepTextColor);
array.recycle();
mOutPaint = new Paint();
mOutPaint.setAntiAlias(true);
mOutPaint.setStrokeWidth(mBorderWidth);
mOutPaint.setColor(mOuterColor);
mOutPaint.setStyle(Paint.Style.STROKE);
mOutPaint.setStrokeCap(Paint.Cap.ROUND);
mInnerPaint = new Paint();
mInnerPaint.setAntiAlias(true);
mInnerPaint.setStrokeWidth(mBorderWidth);
mInnerPaint.setColor(mInnerColor);
mInnerPaint.setStyle(Paint.Style.STROKE);//实心
mInnerPaint.setStrokeCap(Paint.Cap.ROUND);//圆角
mTextPaint = new Paint();
mTextPaint.setAntiAlias(true);
mTextPaint.setStyle(Paint.Style.STROKE);
mTextPaint.setColor(mStepTextColor);
mTextPaint.setTextSize(mStepTextSize);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST) {
//用户设置的是wrap_content,此时设置一个默认宽高100
width = height = MeasureUtils.dp2px(200, this);
}
setMeasuredDimension(width > height ? height : width, width > height ? height : width);
//最后设置宽高
setMeasuredDimension(width > height ? height : width, width > height ? height : width);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int center = getWidth() / 2;
int radius = getWidth() / 2 - mBorderWidth;
RectF rectF = new RectF(mBorderWidth, mBorderWidth, center + radius, center + radius);
canvas.drawArc(rectF, 135, 270, false, mOutPaint);
if (mSeptMax == 0) return; // 如果是0步 就返回
float sweepAngle = (float) mSeptCurrent / mSeptMax;
canvas.drawArc(rectF, 135, 270 * sweepAngle, false, mInnerPaint);
String stepText = mSeptCurrent + "";
Rect textBounds = new Rect();
mTextPaint.getTextBounds(stepText, 0, stepText.length(), textBounds);
int dx = getWidth() / 2 - textBounds.width() / 2;
int baseLine = MeasureUtils.measureBaseLine(mTextPaint, stepText, this);
canvas.drawText(stepText, dx, baseLine, mTextPaint);
}
private int sp2px(int sp) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp,
getResources().getDisplayMetrics());
}
public void setmSeptMax(int mSeptMax) {
this.mSeptMax = mSeptMax;
}
public synchronized void setmSeptCurrent(int mSeptCurrent) {
this.mSeptCurrent = mSeptCurrent;
//重绘
invalidate();
}
}
3,在xml中使用
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.example.view.QView
android:id="@+id/qq"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:outerColor="@color/purple_200"
app:innerColor="@color/purple_700"
app:borderWidth="20dp"
app:stepTextColor="@color/purple_500"
app:stepTextSize="30sp"
/>
</LinearLayout>
工具类
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.TypedValue;
import android.view.View;
public class MeasureUtils {
/**
* drawText获取基线
*
* @param textPaint
* @param text
* @param view
* @return
*/
public static int measureBaseLine(Paint textPaint, String text, View view) {
Rect textBounds = new Rect();
textPaint.getTextBounds(text, 0, text.length(), textBounds);
Paint.FontMetricsInt fontMetricsInt = textPaint.getFontMetricsInt();
int dy = (fontMetricsInt.bottom - fontMetricsInt.top) / 2 - fontMetricsInt.bottom;
int baseLine = view.getHeight() / 2 + dy;
return baseLine;
}
public static int sp2px(int sp, View view) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, view.getResources().getDisplayMetrics());
}
public static int dp2px(int dp, View view) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, view.getResources().getDisplayMetrics());
}
}
4,在Activity中添加动画
import androidx.appcompat.app.AppCompatActivity;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.os.Bundle;
import android.view.animation.DecelerateInterpolator;
public class MainActivity extends AppCompatActivity {
QView customQQStep;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
customQQStep = findViewById(R.id.qq);
customQQStep.setmSeptMax(4000);
//属性动画
ValueAnimator valueAnimator = ObjectAnimator.ofFloat(0, 4000);
valueAnimator.setDuration(5000);
valueAnimator.setInterpolator(new DecelerateInterpolator());//插值器
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float currentStep = (Float) animation.getAnimatedValue();
customQQStep.setmSeptCurrent((int) currentStep);
}
});
valueAnimator.start();
}
}
5效果图