QQ运动的记步进度条实现

原创 2018年04月16日 18:48:56

今天突然看到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;
    }
}

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

源码地址

如何在驱动程序(SYS)中得到当前进程的完整路径和进程名?

 首先利用PsGetCurrentProcess或IoGetCurrentProcess函数得到当前进程的句柄,这个句柄是指向_EPROCESS结构的指针,_EPROCESS的结构如下:typedef...
  • xstudio
  • xstudio
  • 2002-05-08 14:58:00
  • 940

【Android自定义View实战】之仿QQ运动步数圆弧及动画,Dylan计步中的控件StepArcView

在之前的Android超精准计步器开发-Dylan计步中的首页用到了一个自定义控件,和QQ运动的界面有点类似,还有动画效果,下面就来讲一下这个View是如何绘制的。 1.先看效果图2.效果图分析 功能...
  • u010785585
  • u010785585
  • 2016-10-28 08:41:15
  • 4842

Android仿qq健康效果

最近又搞医疗项目,为了搞的高大上一天,仿照最近流行的qq健康的,干才开始自己写了一个用图片做为背景的,感觉太lou了,然后看大神写的,先看看效果吧,最好还是用自定义一个view控件 代码如下pack...
  • baidu_23086307
  • baidu_23086307
  • 2016-06-04 18:42:12
  • 977

小米手环 / 运动手环 记步功能原理

很多朋友是第一次接触像小米手环这类运动计步产品,对于那么轻盈小巧的手环能够精准计步,甚至能详细完整的记录睡眠时间觉得非常神奇,本文就和大家详细说说在看不见的小米手环背板下,它是怎么工作的。 ...
  • u013467442
  • u013467442
  • 2015-03-01 21:36:06
  • 9110

Android计步模块(类似微信运动)

最近在项目中研究计步模块,每天0点开始记录当天的步数,类似微信运动。碰到了不少坑今天有时间整理出来给大家看看。 做之前在google、baidu、github上搜了个遍没找到好的,大多数都是需要在后...
  • qq_24531461
  • qq_24531461
  • 2017-07-13 22:41:06
  • 1071

微信运动刷步教程 QQ健康刷步数(一)之安卓版本 - 乐运动

STEP1:下载乐动力APP(自行上应用市场搜索) 请先下载“乐动力”APP,完成下载后使用微信登录APP。 STEP2:开打乐动力APP>>>进入设置 首先点...
  • qq_21051503
  • qq_21051503
  • 2015-11-05 21:01:33
  • 17412

程序员转产品经理的第一个功能——上传计步信息至QQ健康

程序员转产品经理的第一个功能——上传计步信息至QQ健康 11月11日,没错就是光棍节,马云谱写了一天913 亿元销售额的这天,我的第一个需求终于上线了。终于有脸可以来写一写我的历程,记下来以后每次提...
  • farmer_cc
  • farmer_cc
  • 2015-11-14 00:36:42
  • 2154

Android 计步功能-简单实现

使用Android4.4 Kitkat 新增的STEP DETECTOR 以及 STEP COUNTER传感器。 官方介绍: TYPE_STEP_COUNTER:计...
  • csdnloginname
  • csdnloginname
  • 2016-07-22 21:42:40
  • 14878

Android 4.4后仿华为手机实现计步的效果

在市面上浏览过众多的计步软件,可惜没有开源的代码,而github上的几个开源的计步代码,要么就是记得不准,要么就是功能不完善,不稳定,于是决心自己写一个,分享给大家使用,希望大家一起来完善。 !!!...
  • liu_jing_hui
  • liu_jing_hui
  • 2017-06-30 15:49:37
  • 937

iOS计步器功能实现之CoreMotion(一)

最近公司的app中新增加了一个计步器的功能,从网上了搜到了healthKit可以实现记步功能,但是分析后发现HealthKit应该是调用的苹果自己的API来实现的专门为自身的运动手环,苹果手表,电子称...
  • HHL110120
  • HHL110120
  • 2016-05-29 12:30:14
  • 7281
收藏助手
不良信息举报
您举报文章:QQ运动的记步进度条实现
举报原因:
原因补充:

(最多只允许输入30个字)