QQ运动的记步进度条实现

今天突然看到QQ计步器样式更新了,变的还挺快

我自己构思实现  和QQ还是有差别的但是基本样式实现了。


下来看代码  代码里面基本都全是注释。

package com.zyf.customview.view;

import android.animation.ValueAnimator;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;

import com.zyf.customview.R;

/**
 * 作者:小飞
 * 创建于 2018年4月16日 17:46:36
 */

public class QQCustomView extends View {
    /**
     * 画笔
     * */
    private Paint mPaint;
    /**
     * 文字画笔
     * */
    private Paint mTextPaint;
    /**
     * 文字画笔
     * */
    private Paint mSmallTextPaint;
    /**
     * 填充进度颜色
     * */
    private int insideColor;
    /**
     * 背景颜色
     * */
    private int outsideColor;
    /**
     * 文字颜色
     * */
    private int textColor;
    /**
     * 宽
     * */
    private int width;
    /**
     * 高
     * */
    private int height;
    /**
     * 当前进度条
     * */
    private int currentProgress = 0;
    /**
     * 进度的百分比
     * */
    private int progress;
    /**
     * 文字的高度
     * */
    private int textheight;
    /**
     * 步数
     * */
    private int steps;
    /**
     * 最大步数
     * */
    private int stepsCount = 5000;
    /**
     * 单位
     * */
    private String company;
    /**
     * 弧线的宽度
     * */
    private int arcStrokeWidth = 20;

    /**
     * 弧线的间距
     * */
    private float spacingWidth = 2;
    /**
     * 进度监听
     * */
    private OnViewProgressListener listener;
    public QQCustomView(Context context) {
        this(context,null);
    }

    public QQCustomView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public QQCustomView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray ty = context.getTheme().obtainStyledAttributes(attrs, R.styleable.CustomView,0,0);
        try {
            insideColor = ty.getColor(R.styleable.CustomView_inside_color,0xFF40B3FF);
            outsideColor = ty.getColor(R.styleable.CustomView_outside_color,0xFF737171);
            textColor = ty.getColor(R.styleable.CustomView_text_color,0xFF40B3FF);
            steps = ty.getInt(R.styleable.CustomView_step,0);
            stepsCount = ty.getInt(R.styleable.CustomView_step_count,5000);
            company = ty.getString(R.styleable.CustomView_company);
            arcStrokeWidth = ty.getInt(R.styleable.CustomView_arc_stroke_width,20);
            if(TextUtils.isEmpty(company)){
                company = "步";
            }
        }finally {
            ty.recycle();
        }
        init();
    }
    /**
     * 初始化属性
     *  <attr name="inside_color" format="color"></attr>
     *  <attr name="outside_color" format="color"></attr>
     *  <attr name="text_color" format="color"></attr>
     * */
    private void init() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setStrokeWidth(5);
        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
        mTextPaint.setTextSize(100);
        mTextPaint.setColor(textColor);
        textheight = (int)(mTextPaint.ascent()+mTextPaint.descent());
        mSmallTextPaint = new Paint();
        mSmallTextPaint.setAntiAlias(true);
        mSmallTextPaint.setTextSize(50);
        mSmallTextPaint.setColor(textColor);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        width = measureSize(widthMeasureSpec);
        height = measureSize(heightMeasureSpec);
        setMeasuredDimension(width,height);
    }
    private int measureSize(int measureSpec) {
        int length;
        int mode = MeasureSpec.getMode(measureSpec);
        int size = MeasureSpec.getSize(measureSpec);
        if(mode == MeasureSpec.EXACTLY){
            length = size;
        }else{
            length = 500;
            if(mode == MeasureSpec.AT_MOST){
                length = Math.min(length,size);
            }
        }
        return length;
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if(listener!=null){
            listener.onProgress(currentProgress);
        }
        drawInside(canvas);
        drawOutside(canvas,currentProgress);
        drawText(canvas,currentProgress);
    }
    /**
     * 画字
     * */
    private void drawText(Canvas canvas,int steps) {
        String str = steps+"";
        int textWidth = (int)mTextPaint.measureText(str);
        int textsWidth = (int)mSmallTextPaint.measureText(company);
        int countWidth = textsWidth +textWidth;
        canvas.drawText(str,0,str.length(),(width-countWidth)/2,(height-textheight)/2,mTextPaint);
        canvas.drawText(company,0,1,(width+textWidth-textsWidth)/2,(height-textheight)/2,mSmallTextPaint);
    }

    /**
     * 画背景
     * */
    private void drawInside(Canvas canvas) {
        mPaint.setColor(outsideColor);
        canvas.save();
        //这里270的意思是旋转270的弧线的意思
        //(float) (width/2 + width/2 * Math.cos(135f*Math.PI/180))
        // 计算的是 135度的情况下 圆上的点位置  计算两个同一半径直线上的两个点画线 旋转画布角度  重复画  就达到了所有的刻度
        for (float i = 0; i < 270/spacingWidth; i++) {
            canvas.drawLine((float) (width/2 + width/2 * Math.cos(135f*Math.PI/180)),(float) (height/2 + (width/2) * Math.sin(135f*Math.PI/180)),
                    (float) (width/2 + (width/2-arcStrokeWidth) * Math.cos(135f*Math.PI/180)),(float) (height/2 + (width/2-arcStrokeWidth) * Math.sin(135f*Math.PI/180)), mPaint);
            canvas.rotate(spacingWidth, getWidth() / 2, getHeight() / 2);
        }
        canvas.restore();
    }

    /**
     * 画进度
     * */
    private void drawOutside(Canvas canvas,int progress) {
        float angle;
        if((progress/(stepsCount*1f))*270>270){
            angle = 270;
        }else {
            angle =  (progress/(stepsCount*1f))*270;
        }
        mPaint.setColor(insideColor);
        mPaint.setStyle(Paint.Style.STROKE);
        canvas.save();
        for (float i = 0; i < angle/spacingWidth; i++) {
            canvas.drawLine((float) (width/2 + width/2 * Math.cos(135f*Math.PI/180)),(float) (height/2 + (width/2) * Math.sin(135f*Math.PI/180)),
                    (float) (width/2 + (width/2-arcStrokeWidth) * Math.cos(135f*Math.PI/180)),(float) (height/2 + (width/2-arcStrokeWidth) * Math.sin(135f*Math.PI/180)), mPaint);
            canvas.rotate(spacingWidth, getWidth() / 2, getHeight() / 2);
        }
        canvas.restore();
    }
    /**
     * 设置当前进度
     * */
    public void setCurrentProgress(int currentProgress) {
        this.currentProgress = currentProgress;
        invalidate();
    }
    /**
     * 属性动画
     * */
    ValueAnimator anim;
    private void animatorMethod(){
        if(anim!=null&&anim.isRunning()){
            return;
        }
        anim = ValueAnimator.ofInt(0,steps);
        anim.setDuration(3000);
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                currentProgress = (int)animation.getAnimatedValue();
                invalidate();
            }
        });
        anim.start();

    }

    public void setSteps(int steps) {
        this.steps = steps;
        animatorMethod();
    }
    /**
     * 设置线条宽度
     * */
    public void setArcStrokeWidth(int arcStrokeWidth) {
        if(arcStrokeWidth<10){
            return;
        }
        this.arcStrokeWidth = arcStrokeWidth;
        invalidate();
    }
    /**
     * 设置线条间距
     * */
    public void setSpacingWidth(float spacingWidth) {
        if(spacingWidth<1){
            return;
        }
        this.spacingWidth = spacingWidth;
        invalidate();
    }

    public interface OnViewProgressListener{
        void onProgress(int progress);
    }
    /**
     * 设置监听
     * */
    public void setListener(OnViewProgressListener listener) {
        this.listener = listener;
    }
}

里面的自定义属性不用关注 上面有属性注释  自己也可以直接初始化即可

源码地址

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值