解析請看這自定義View-仿QQ運動步數(shù)進度效果
一、attrs.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="centerTextSize" format="dimension"/>
<!-- 外圍圓弧大小-->
<attr name="cirleSize" format="dimension"/>
<!-- 步婁文字顏色大小-->
<attr name="centerTextColor" format="color"/>
<!-- 外圍圓弧顏色-->
<attr name="cirleForeginColor" format="color"/>
<!-- 內圍圓弧顏色-->
<attr name="centerInnerColor" format="color"/>
</declare-styleable>
</resources>
二、ProgressRunView
package com.example.myapplication.Widget;
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.util.Log;
import android.util.TypedValue;
import android.view.View;
import androidx.annotation.Nullable;
import com.example.myapplication.R;
public class ProgressRunView extends View {
/**
* 畫筆的設置
*/
private Paint paintText;
private Paint paintCirle;
private Paint paintCirleInner;
private int centerTextSize = 20;
private float cirleSize = 1;
private int centerTextColor = Color.BLUE;
private int cirleForeginColor = Color.BLUE;
private int centerInnerColor = Color.RED;
private Context context;
/**
* 屬性獲取
*/
private int x;
private int y;
public ProgressRunView(Context context) {
super(context);
}
public ProgressRunView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
this.context = context;
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ProgressRunView);
centerTextSize = typedArray.getDimensionPixelSize(R.styleable.ProgressRunView_centerTextSize,Px2Sp(context,centerTextSize));
cirleSize = typedArray.getDimension(R.styleable.ProgressRunView_cirleSize,cirleSize);
centerTextColor = typedArray.getColor(R.styleable.ProgressRunView_centerTextColor,centerTextColor);
cirleForeginColor = typedArray.getColor(R.styleable.ProgressRunView_cirleForeginColor,cirleForeginColor);
centerInnerColor = typedArray.getColor(R.styleable.ProgressRunView_centerInnerColor,centerInnerColor);
typedArray.recycle();
paintText = new Paint();
paintText.setColor(centerTextColor);
paintText.setTextSize(centerTextSize);
paintText.setAntiAlias(true);
paintText.setDither(true);
paintCirle = new Paint();
paintCirle.setColor(cirleForeginColor);
//設置畫筆的寬
paintCirle.setStrokeWidth(20);
paintCirle.setStrokeCap(Paint.Cap.ROUND);
paintCirle.setStrokeJoin(Paint.Join.ROUND);
paintCirle.setStyle(Paint.Style.STROKE);
paintCirle.setAntiAlias(true);
paintCirle.setDither(true);
paintCirleInner = new Paint();
paintCirleInner.setColor(centerInnerColor);
//設置畫筆的寬
paintCirleInner.setStrokeWidth(18);
paintCirleInner.setStrokeCap(Paint.Cap.ROUND);
paintCirleInner.setStrokeJoin(Paint.Join.ROUND);
paintCirleInner.setStyle(Paint.Style.STROKE);
paintCirleInner.setAntiAlias(true);
paintCirleInner.setDither(true);
}
public ProgressRunView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//獲取寬高的模式
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
//指定寬高的大小
int width = MeasureSpec.getSize(widthMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
//如果寬高設置為wrap_content時,剛默認為500
if(widthMode == MeasureSpec.AT_MOST || heightMode == MeasureSpec.AT_MOST){
width = 500;
height = width;
}
//如果寬高不一致時,則以寬為標準
if(width != height){
height = width;
}
setMeasuredDimension(width,height);
}
@Override
protected void onDraw(Canvas canvas) {
drawText(canvas);
drawCirle(canvas);
drawCirleInner(canvas);
}
/**
* 繪制內弧
* @param canvas
*/
private void drawCirleInner(Canvas canvas) {
int radius = 200;
RectF rectF = new RectF(x-radius,y-radius,x + radius,y+ radius);
float sweepAngle = (float) Integer.valueOf(runText)/maxStep;
//動態(tài)設置掃過的面積(弧的動態(tài)效果)
canvas.drawArc(rectF, 135, sweepAngle*270, false, paintCirleInner);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
//獲取中心點
x = (right - left)/2;
y = (bottom - top)/2;
}
/**
* 繪制外弧
* @param canvas
*/
private void drawCirle(Canvas canvas) {
int radius = 200;
RectF rectF = new RectF(x-radius,y-radius,x + radius,y+ radius);
canvas.drawArc(rectF, 135, 270, false, paintCirle);
}
private String runText = "0";
/**
* 繪制中間的文本
* @param canvas
*/
private void drawText(Canvas canvas) {
Rect rect = new Rect();
paintText.getTextBounds(runText,0,runText.length(),rect);
Paint.FontMetrics fontMetrics =paintText.getFontMetrics();
int dx = getWidth()/2 - rect.width()/2;
//基線
float baseline = getHeight()/2 + (fontMetrics.top-fontMetrics.bottom)/2-fontMetrics.top;
canvas.drawText(runText,dx,baseline,paintText);
}
/**
* Sp轉Px
* @param context
* @param px
* @return
*/
public int Px2Sp(Context context, int px) {
return (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,px,context.getResources().getDisplayMetrics());
}
/**
* 步數(shù)的重新繪制
* @param progress
*/
public synchronized void setProgress(int progress) {
this.runText = String.valueOf(progress);
// 重新刷新繪制 -> onDraw()
invalidate();
}
/**
* 設置最大值
* @param maxStep
*/
public synchronized void setMaxStep(int maxStep) {
this.maxStep = maxStep;
}
private int maxStep;
/**
* 開始運行
* @param start 開始的大小
* @param end 結束的大小
*/
public void start(int start,int end){
ValueAnimator valueAnimator = ValueAnimator.ofInt(start,end);
//開始到結束的時間
valueAnimator.setDuration(3000);
valueAnimator.start();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator valueAnimator) {
int currentStep = (int) valueAnimator.getAnimatedValue();
//設置當前的步數(shù)并重新繪制
setProgress(currentStep);
Log.e("onAnimationUpdate: ", String.valueOf(currentStep));
}
});
}
}
三、Activity
package com.example.myapplication;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import androidx.appcompat.app.AppCompatActivity;
import com.example.myapplication.InterfaceCalkable.ScrollCallBack;
import com.example.myapplication.Widget.ProgressRunView;
import com.example.myapplication.Widget.ProgressView;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private ProgressRunView progressRunView;
private Button btn_run;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
progressRunView = (ProgressRunView) findViewById(R.id.progressRunView);
progressRunView.setMaxStep(5000);
btn_run = (Button) findViewById(R.id.btn_run);
btn_run.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_run:
progressRunView.start(0,3650);
break;
}
}
}