天天看点

自定义View-仿QQ运动步数进度效果(完整代码)一、attrs.xml二、ProgressRunView三、Activity

解析请看这自定义View-仿QQ运动步数进度效果

一、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;
        //动态设置扫过的面积(弧的动态效果)
        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());
    }

    /**
     * 步数的重新绘制
     * @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();
                //设置当前的步数并重新绘制
                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;
        }
    }
}