android 自定义view实现仿QQ运动步数进度效果

Android获取华为运动健康数据(以总步数为例) 博主现在是刚毕业的学生,因此技术还有些欠缺,希望能通过编写博客来提升和记录自己的一些工作经验。 由于还没正式帮项目组干活,项目组的头就让我先做点之后可能要做的功能,这次是让我在一个负一屏的应用上,用一个卡牌来显示今日的总步数。之前在网上找了很多方法后,发现只能从0开始计步或者是获取开机之后的总步数,达不到要实现的要求,最后,还是想通过接入华为的API来直接实现获取步数的功能。其实,华为的开发者文档已经写的很详细了,但是华为写的不一定一看就懂,在这里我就记录一下实现的具体流程,写的简单易懂一点,希望能帮到要 阅读详情

最近公司在策划一个新的项目,原型还没出来,再说这公司人都要走没了,估计又要找工作了,所以必须要学习,争取每个写个关于自定义view方面的,这样几个月积累下来,也能学习到东西,今天就带来简单的效果,就是仿QQ运动步数的进度条效果.在这就不分析了,直接贴代码,

自定义属性:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="QQMovementView">
        <attr name="defaultCircleColor" format="color|reference"></attr>
        <attr name="ProgressColor" format="color|reference"></attr>
        <attr name="CustomTextColor" format="color|reference"></attr>
        <attr name="CustomTextSize" format="dimension|reference"></attr>
        <attr name="BorderWidth" format="integer|reference"></attr>
        <attr name="ProgressMax" format="integer|reference"></attr>
        <attr name="currentProgress" format="integer|reference"></attr>
        <attr name="CustomStartAngle" format="integer|reference"></attr>
        <attr name="CustomSweepAngle" format="integer|reference"></attr>
    </declare-styleable>
</resources>

自定义View

package com.day01;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.RectF;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
/**
 * Created by zhouguizhijxhz on 2018/5/24.
 */
public class QQMovementView extends View {
    private static final String TAG = "QQMovementView";
    private Paint progressPaint;
    private Paint textPaint;
    private Paint circlePaint;
    private int defaultCircleColor = Color.parseColor("#FF82AB");
    private int defaultTextColor = Color.parseColor("#ff3f3f");
    private int defaultTextSize = 24;
    private int borderWidth = 12;
    private int progressColor = Color.parseColor("#FFA07A");
    private int max = 100;
    private int currentProgress = 10;
    private int startAngle = 135;
    private int sweepAngle = 270;

    public QQMovementView(Context context) {
        this(context, null);
    }

    public QQMovementView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public QQMovementView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttrs(context, attrs);
        initTextPaint(context);
        initCirclePaint();
        initProgressPaint();
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int width = measureWidth(widthMeasureSpec);
        int height = measureHeight(heightMeasureSpec);
        setMeasuredDimension(Math.min(width, height), Math.min(width, height));
    }

    private int measureHeight(int heightMeasureSpec) {
        int mode = MeasureSpec.getMode(heightMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        if (mode == MeasureSpec.AT_MOST) {
            height = 360;
        }
        return height;
    }

    private int measureWidth(int widthMeasureSpec) {
        int mode = MeasureSpec.getMode(widthMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);
        if (mode == MeasureSpec.AT_MOST) {
            width = 360;
        }
        return width;
    }

    private void initProgressPaint() {
        progressPaint = new Paint();
        progressPaint.setColor(progressColor);
        progressPaint.setStrokeWidth(borderWidth);
        progressPaint.setStyle(Paint.Style.STROKE);
        progressPaint.setStrokeCap(Paint.Cap.ROUND);
        progressPaint.setAntiAlias(true);
    }

    private void initCirclePaint() {
        circlePaint = new Paint();
        circlePaint.setColor(defaultCircleColor);
        circlePaint.setStrokeWidth(borderWidth);
        circlePaint.setStyle(Paint.Style.STROKE);
        circlePaint.setStrokeCap(Paint.Cap.ROUND);
        circlePaint.setAntiAlias(true);
    }

    private void initTextPaint(Context context) {
        textPaint = new Paint();
        textPaint.setColor(defaultTextColor);
        textPaint.setTextSize(sp2px(context,defaultTextSize));
    }

    private void initAttrs(Context context, AttributeSet attrs) {
        if (null == context || null == attrs) {
            return;
        }
        TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.QQMovementView);
        defaultCircleColor = typedArray.getColor(R.styleable.QQMovementView_defaultCircleColor, defaultCircleColor);
        defaultTextColor = typedArray.getColor(R.styleable.QQMovementView_CustomTextColor, defaultTextColor);
        defaultTextSize = typedArray.getDimensionPixelSize(R.styleable.QQMovementView_CustomTextSize, defaultTextSize);
        progressColor = typedArray.getColor(R.styleable.QQMovementView_ProgressColor, progressColor);
        borderWidth = typedArray.getInteger(R.styleable.QQMovementView_BorderWidth, borderWidth);
        max = typedArray.getInteger(R.styleable.QQMovementView_ProgressMax,max);
        currentProgress = typedArray.getInteger(R.styleable.QQMovementView_currentProgress,currentProgress);
        startAngle = typedArray.getInteger(R.styleable.QQMovementView_CustomStartAngle,startAngle);
        sweepAngle = typedArray.getInteger(R.styleable.QQMovementView_CustomSweepAngle,sweepAngle);
        Log.e(TAG,"max--->"+max);
        Log.e(TAG,"currentProgress--->"+currentProgress);
        typedArray.recycle();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        drawArc(canvas);
        drawProgressArc(canvas);
        drawProgressText(canvas);
    }

    private void drawProgressText(Canvas canvas) {
        if (null == canvas) {
            return;
        }
        String strPercent = String.valueOf(currentProgress);
        Paint.FontMetricsInt fm = textPaint.getFontMetricsInt();
        canvas.drawText(strPercent, getWidth() / 2 - textPaint.measureText(strPercent) / 2,
                getHeight() / 2 - (fm.bottom + fm.top) / 2, textPaint);
    }

    private void drawProgressArc(Canvas canvas) {
        if (null == canvas) {
            return;
        }
        if (max == 0) {
            return;
        }
        if (currentProgress == 0) {
            return;
        }
        RectF rectF = new RectF(borderWidth / 2, borderWidth / 2, getMeasuredWidth() - borderWidth / 2, getMeasuredHeight() - borderWidth / 2);
        float percent = (float) currentProgress / max;
        Log.e(TAG,"percent------->"+percent);
        canvas.drawArc(rectF, startAngle, sweepAngle * percent, false, progressPaint);
    }

    private void drawArc(Canvas canvas) {
        if (null == canvas) {
            return;
        }
        RectF rectF = new RectF(borderWidth / 2, borderWidth / 2, getMeasuredWidth() - borderWidth / 2, getMeasuredHeight() - borderWidth / 2);
        canvas.drawArc(rectF, startAngle, sweepAngle, false, circlePaint);
    }

    public static int sp2px(Context context, float spValue) {
        final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (spValue * fontScale + 0.5f);
    }

    public void setMax(int max) {
        this.max = max;
    }

    public void setCurrentProgress(int currentProgress) {
        this.currentProgress = currentProgress;
    }
}

布局:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <com.day01.QQMovementView
        android:layout_width="240dp"
        android:layout_height="240dp"
        android:layout_centerHorizontal="true"
        android:layout_marginRight="60dp"
        android:layout_marginTop="60dp"
        app:currentProgress="30"
        app:ProgressMax="200"
         />
</RelativeLayout>

效果:


步数,仪表盘等显示进度progressBar 立即下载

相关推荐

类似于运动刻度表的计步器UI界面

类似于刻度表的计步器UI界面,中间数字代表步数

Android获取华为运动健康数据(以总步数为例)_android 获取运动信息

第一次写博客,可能写的不是很全,写一半的时候也有点不想写了,但是还是坚持写完了,希望以上经验能帮到大家,如果有什么问题的话,可以在评论中提出,会尽量为大家解决的哦。① 2000多本Python电子书(主流和经典的书籍应该都有了)② Python标准库资料(最全中文版)③ 项目源码(四五十个有趣且经典的练手项目及源码)④ Python基础入门、爬虫、web开发、大数据分析方面的视频(适合小白学习)⑤ Python学习路线图(告别不入流的学习)

2401_84573447的博客 3599

Android-仿QQ运动等APP中运动步数显示View

仿QQ运动等APP中运动步数显示View

Android实现计步器(附带源码)

Android实现计步器(附带源码)

欢迎来到我的博客!这里是一个专注于计算机技术的分享平台,涵盖编程开发、算法研究、系统架构、软件工程等多个领域。无论你是初学者还是资深开发者,都能在这里找到有价值的内容。 1864

一款非常绚丽的进度条

Android 加载动画(关于SpinKit的使用) @style/SpinKitView @style/SpinKitView.Circle @style/SpinKitView.Large @style/SpinKitView.Small @style/SpinKitView.Small.DoubleBounce

Android的圆弧进度动画代码例子

Android的圆弧动画代码例子,可用于描述下载进度,以及某个事件的完成百分比

Android手机步数怎么统计的,手机中运动步数是如何计算的?(15个回答)

微信运动每天都记录着你走路的步数,他会形成榜单,走的多收到很多赞,走的少则无人关注,如果你走到第一,你的照片将霸占排行榜封面。所以一段时间,每个人为了霸占封面疯狂走路、刷步,然而有时我们却发现你跟好友一起走的路,最终你却比他步数少,这是为什么?或者你想通过跑步来增加步数,但是底有效没?下面我们亲身试验告诉你答案。test 1走相同路记步不一样?其实全看命一人拿两部手机,测出来的步数肯定是一样的?如...

weixin_39585617的博客 3248

告别手动画图!用SUMO的netedit快速搭建高速公路交织区路网(附完整XML文件)

本文详细介绍了如何使用SUMO的netedit工具高效构建高速公路交织区路网,避免手动绘图的低效与错误。通过实战案例和XML文件示例,帮助交通工程专业学生快速掌握复杂道路结构建模技巧,特别解析了spreadType参数设置和速度单位换算等关键操作。

weixin_29085865的博客 261

69、Android获取每日运动步数

Android获取每日运动步数

lanxuan1993的博客 5408

【QGIS】利用“创建网格”功能实现区域等距分割与坐标转换实战

本文详细介绍了如何在QGIS中使用“创建网格”工具实现区域等距分割。通过实战演示,将北京市行政区划切割为150米正方形网格,并重点讲解了关键步骤:选择投影坐标系EPSG:3857以确保网格尺寸精确,以及将结果转换为常用的WGS84经纬度坐标。文章还涵盖了进阶技巧与常见问题解决方案,帮助用户高效完成空间网格化分析任务。

weixin_29232507的博客 96

Vivado2022.2下载安装

链接:https://pan.baidu.com/s/1lyfE2d-VmaWC-_aR8ratCQ提取码:mt09。

weixin_61081689的博客 2万+

Android 系统(264)---android进阶——自定义View

android进阶——自定义View   软件架构 01.自定义View简介 - onMeasure,onDraw,自定义属性 https://www.jianshu.com/p/48944aad2000 02.自定义View入门 - 自定义TextView https://www.jianshu.com/p/7b5e4f5abb74 03.自定义View - 仿QQ运动步数进度效果 h...

zhangbijun1230的专栏 387

【数学建模】 进化计算与群体智能

遗传算法(GA)是一种用于优化和搜索问题的启发式算法。它模拟了自然选择的过程,其中个体通过遗传和变异进行繁殖,逐渐进化出更优的解。基本步骤初始化:生成初始种群。适应度评估:评估种群中每个个体的适应度。选择:根据适应度选择个体进行繁殖。交叉:选定个体对进行基因交换,生成新的后代。变异:对一些个体进行基因变异,以增加多样性。迭代:重复评估和繁殖过程,直至达到停止条件。粒子群优化算法(PSO)是一种基于群体智能的优化算法,由Kennedy和Eberhart于1995年提出。其灵感来源于鸟群觅食的行为。

weixin_42914989的博客 1113

自定义View-仿QQ运动步数进度效果

自定义View-仿QQ运动步数进度效果一、写在前面(1) 图一,仿QQ步数运行效果完整代码请看这二、正文开始(1)首先来个三部曲,自定义属性,布局设置,属性获取1)自定义属性,新建attrs.xml2)布局设置3)属性获取(2) 我们先来解决,宽高的问题,重写onMeasure方法(3) 现在就是各种绘制1)绘制文本2)绘制外弧3)绘制内弧文本的动态效果(4)最后在Activity中应用 一、写在前面 在参考了红橙Darren的文章之后,将自己实现的做个笔记,并提供给大家参考,红橙Darren 的 自定义V

不蚊 588

让 ABAP 复杂内表优雅“喂饱”:Complex Internal Table Filling 全面实战指南

本文为ABAP开发者系统梳理了复杂内表的填充与复制方法。重点介绍了work area的两种声明方式、APPEND操作的多形态用法及其初始值语义,以及VALUE #( )构造器的逐行与整表写法。同时讲解了CORRESPONDING的同名字段映射功能,帮助开发者在"航司与航线"等复杂业务场景中实现最佳实践。文章还涵盖内存优化、可读性建议和常见误区,提供可运行样例,适用于ABAP On-Premise和SAP BTP环境。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 169

使用LSTM实现自动调制识别(RML2018.01a)

目录一、LSTM的代码实现1.1 导入包1.2 数据读取及数据集划分1.3 数据预处理1.4 构建LSTM模型 本文基于RML2018.01a大型数据集,给出LSTM的信号识别的实现方式(附代码) RML2018.01a数据集信息如下: 模型 传送门 CNN/ResNet 使用CNN/ResNet实现自动调制识别(RML2018.01a) LSTM 使用LSTM实现自动调制识别(RML2018.01a)) 一、LSTM的代码实现 1.1 导入包 import numpy as np

QAQIknow的博客 6123

自定义View之仿QQ运动步数进度效果

前言 今天接着上一篇来写关于自定义View方面的东西,因为我近期也是在学习整理这方面的知识点,所以我把学习的笔记都写成博文放到这个Android自定义View的专栏里了,仅作为自己学习笔记所用,今天的内容是关于Paint画笔方面的一个应用,做一个Demo——仿QQ运动步数进度效果。 一、案例效果分析 首先上一张效果图,大家一起来看一下: 通过上面的这张图,我们来分析一下,该如何去实现...

江湖人陆仁甲 557

基于MATLAB的奇异谱分析(SSA)算法详解

本文详细介绍了基于MATLAB的奇异谱分析(SSA)算法。文章首先阐述了SSA的基本概念、历史发展及其与传统信号分析方法的对比优势,指出SSA作为一种非参数、非线性时间序列分析方法,特别适合处理非平稳信号。随后详细解析了SSA算法的核心原理与数学模型,包括轨迹矩阵构建、奇异值分解、分组与重构四个关键步骤。文章还提供了完整的MATLAB实现框架和代码解析,涵盖参数检查、轨迹矩阵构建、SVD分解、分组策略和重构过程。最后,通过信号分解、去噪和预测三个应用案例展示了SSA的实际效果。

qq_42212808的博客 168

Android自定义View之仿QQ运动步数进度效果

文章目录前言先看效果图 ![在这里插入图片描述](https://img-blog.csdnimg.cn/6e4ddec17933496ea4830fa08d8ffbe5.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM1ODU3NDUx,size_16,color_FFFFFF,t_70#pic_center)一、实现思路二、实现步骤1

qq_35857451的博客 889

成功解决 OllamaError: status code 400, message: model ‘llama3.2:latest‘ not found 报错

本文针对Ollama更新后出现的OllamaError: status code 400, message: model 'llama3.2:latest' not found报错,分析了其根本原因——2026年1月Ollama将Llama 3.2模型命名从llama3.2:latest改为meta-llama/Llama-3.2:7b-instruct等新格式。解决方案包括:1)使用新模型名称;2)升级Ollama SDK;3)查询确认本地可用模型;4)批量更新旧项目脚本。通过正确适配新命名规则,

博客 1398

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

自定义View学习之仿QQ运动步数进度效果

自定义View学习的小记录之第一篇自定义View学习之QQ计步器如何实现1.分析想要得到什么效果2.确定自定义属性,编写attrs.xml3.在布局中使用4.在自定义View中获取自定义属性5.onMeasure()得到这个控件的的大小6.再去画具体的控件,绘制外圆弧和内圆弧、相关的文本文字7.其他功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生...

weixin_42600795的博客 477

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

自定义View | 仿QQ运动步数进度效果

项目GitHub地址 思路 固定不动的蓝色大圆弧 动画变动的红色小圆弧 中间的步数文字显示 相关的自定义属性 比如固定不动的大圆弧, 我们不能写死他的蓝色颜色属性, 要提供一个颜色的自定义属性给用户自定义配置; 圆弧的宽度也是要可以自定义的; 自定义属性 <?xml version="1.0" encoding="utf-8"?> <resources> ... ...

aaLiweipeng的博客 379

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

android计步器简书,自定义View-仿QQ运动步数进度效果

自定义View-仿QQ运动步数进度效果一、写在前面(1) 图一,仿QQ步数运行效果(2) 图二,完整的圆效果完整代码请看这二、正文开始(1)首先来个三部曲,自定义属性,布局设置,属性获取1)自定义属性,新建attrs.xml2)布局设置3)属性获取(2) 我们先来解决,宽高的问题,重写onMeasure方法(3) 现在就是各种绘制1)绘制文本2)绘制外弧3)绘制内弧4)文本的动态效果(4)最后在A...

weixin_36323859的博客 271

自定义View - 仿QQ运动步数效果

今天我们实现下面这样的效果: 首先自定义属性: <?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="MyQQStep"> <attr name="out_color" format="color"/> ...

qq_36428821的博客 375

重学 Android 自定义 View 系列(三):自定义步数进度条

前言本篇文章主要是实现仿QQ步数View,很老的一个View了,但技术永不落后,开搂!最终效果如下:1. 结构分析QQStepView 主要由三个元素组成:显示一个圆环进度条,通过外环和内环的角度变化来表示进度。支持自定义外环颜色、内环颜色、进度文本颜色和文本大小,这些都可以通过 XML 属性来配置。支持动态更新进度,通过...

cnzzs的博客 983
上一篇: android 使用代理模式切换不同的框架
下一篇: android 自定义view实现应用宝进度条下载效果
zhoushenxian
博客等级 码龄12年 453粉丝 549原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值