在之前的Android超精准计步器开发-Dylan计步中的首页用到了一个自定义控件,和QQ运动的界面有点类似,还有动画效果,下面就来讲一下这个View是如何绘制的。

1.先看效果图

2.效果图分析

功能说明:黄色的代表用户设置的总计划锻炼步数,红色的代表用户当前所走的步数。

初步分析:完全自定义View重写onDraw()方法,画圆弧。

3.画一个圆弧必备知识

在Canvas中有一个画圆弧的方法

drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)//画弧,

参数一是RectF对象,一个矩形区域椭圆形的界限用于定义在形状、大小、电弧,

参数二是起始角(度)在电弧的开始,圆弧起始角度,单位为度。

参数三圆弧扫过的角度,顺时针方向,单位为度,从右中间开始为零度。

参数四是如果是true(真)的话,在绘制圆弧时将圆心包括在内,通常用来绘制扇形;如果是false(假)这将是一个弧线。

参数五是Paint对象;

对于这个方法,大家可以看一下我手绘的草图,比较烂,表达一下这几个参数的意思和绘制过程,画得不好望大家见谅!

4.绘图的准备工作

(1).获取中心点坐标

/**中心点的x坐标*/

float centerX = (getWidth()) / 2;

(2).建立一个圆弧外的参考矩形

/**指定圆弧的外轮廓矩形区域*/

RectF rectF = new RectF(0 + borderWidth, borderWidth, 2 * centerX - borderWidth, 2 * centerX - borderWidth);

5.绘图的主要步骤

(1).【第一步】绘制整体的黄色圆弧

/**

* 1.绘制总步数的黄色圆弧

*

* @param canvas 画笔

* @param rectF 参考的矩形

*/

private void drawArcYellow(Canvas canvas, RectF rectF) {

Paint paint = new Paint();

/** 默认画笔颜色,黄色 */

paint.setColor(getResources().getColor(R.color.yellow));

/** 结合处为圆弧*/

paint.setStrokeJoin(Paint.Join.ROUND);

/** 设置画笔的样式 Paint.Cap.Round ,Cap.SQUARE等分别为圆形、方形*/

paint.setStrokeCap(Paint.Cap.ROUND);

/** 设置画笔的填充样式 Paint.Style.FILL :填充内部;Paint.Style.FILL_AND_STROKE :填充内部和描边; Paint.Style.STROKE :仅描边*/

paint.setStyle(Paint.Style.STROKE);

/**抗锯齿功能*/

paint.setAntiAlias(true);

/**设置画笔宽度*/

paint.setStrokeWidth(borderWidth);

/**绘制圆弧的方法

* drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)//画弧,

参数一是RectF对象,一个矩形区域椭圆形的界限用于定义在形状、大小、电弧,

参数二是起始角(度)在电弧的开始,圆弧起始角度,单位为度。

参数三圆弧扫过的角度,顺时针方向,单位为度,从右中间开始为零度。

参数四是如果这是true(真)的话,在绘制圆弧时将圆心包括在内,通常用来绘制扇形;如果它是false(假)这将是一个弧线,

参数五是Paint对象;

*/

canvas.drawArc(rectF, startAngle, angleLength, false, paint);

}

(2).【第二步】绘制当前进度的红色圆弧

/**

* 2.绘制当前步数的红色圆弧

*/

private void drawArcRed(Canvas canvas, RectF rectF) {

Paint paintCurrent = new Paint();

paintCurrent.setStrokeJoin(Paint.Join.ROUND);

paintCurrent.setStrokeCap(Paint.Cap.ROUND);//圆角弧度

paintCurrent.setStyle(Paint.Style.STROKE);//设置填充样式

paintCurrent.setAntiAlias(true);//抗锯齿功能

paintCurrent.setStrokeWidth(borderWidth);//设置画笔宽度

paintCurrent.setColor(getResources().getColor(R.color.red));//设置画笔颜色

canvas.drawArc(rectF, startAngle, currentAngleLength, false, paintCurrent);

}

(3).【第三步】绘制当前进度的红色数字

/**

* 3.圆环中心的步数

*/

private void drawTextNumber(Canvas canvas, float centerX) {

Paint vTextPaint = new Paint();

vTextPaint.setTextAlign(Paint.Align.CENTER);

vTextPaint.setAntiAlias(true);//抗锯齿功能

vTextPaint.setTextSize(numberTextSize);

Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL);

vTextPaint.setTypeface(font);//字体风格

vTextPaint.setColor(getResources().getColor(R.color.red));

Rect bounds_Number = new Rect();

vTextPaint.getTextBounds(stepNumber, 0, stepNumber.length(), bounds_Number);

canvas.drawText(stepNumber, centerX, getHeight() / 2 + bounds_Number.height() / 2, vTextPaint);

}

(4).【第四步】绘制”步数”的红色数字

/**

* 4.圆环中心[步数]的文字

*/

private void drawTextStepString(Canvas canvas, float centerX) {

Paint vTextPaint = new Paint();

vTextPaint.setTextSize(dipToPx(16));

vTextPaint.setTextAlign(Paint.Align.CENTER);

vTextPaint.setAntiAlias(true);//抗锯齿功能

vTextPaint.setColor(getResources().getColor(R.color.grey));

String stepString = "步数";

Rect bounds = new Rect();

vTextPaint.getTextBounds(stepString, 0, stepString.length(), bounds);

canvas.drawText(stepString, centerX, getHeight() / 2 + bounds.height() + getFontHeight(numberTextSize), vTextPaint);

}

6.动画是如何实现的->ValueAnimator

ValueAnimator是整个属性动画机制当中最核心的一个类,属性动画的运行机制是通过不断地对值进行操作来实现的,而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。它的内部使用一种时间循环的机制来计算值与值之间的动画过渡, 我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。

/*为进度设置动画

* @param start 初始值

* @param current 结束值

* @param length 动画时长

*/

private void setAnimation(float start, float current, int length) {

ValueAnimator progressAnimator = ValueAnimator.ofFloat(start, current);

progressAnimator.setDuration(length);

progressAnimator.setTarget(currentAngleLength);

progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

/**每次在初始值和结束值之间产生的一个平滑过渡的值,逐步去更新进度*/

currentAngleLength = (float) animation.getAnimatedValue();

invalidate();

}

});

progressAnimator.start();

}

7.整个自定义StepArcView的源码

import android.animation.ValueAnimator;

import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Paint;

import android.graphics.Rect;

import android.graphics.RectF;

import android.graphics.Typeface;

import android.util.AttributeSet;

import android.view.View;

import cn.bluemobi.dylan.step.R;

/**

* Created by DylanAndroid on 2016/5/26.

* 显示步数的圆弧

*/

public class StepArcView extends View {

/**

* 圆弧的宽度

*/

private float borderWidth = 38f;

/**

* 画步数的数值的字体大小

*/

private float numberTextSize = 0;

/**

* 步数

*/

private String stepNumber = "0";

/**

* 开始绘制圆弧的角度

*/

private float startAngle = 135;

/**

* 终点对应的角度和起始点对应的角度的夹角

*/

private float angleLength = 270;

/**

* 所要绘制的当前步数的红色圆弧终点到起点的夹角

*/

private float currentAngleLength = 0;

/**

* 动画时长

*/

private int animationLength = 3000;

public StepArcView(Context context) {

super(context);

}

public StepArcView(Context context, AttributeSet attrs) {

super(context, attrs);

}

public StepArcView(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

}

@Override

protected void onDraw(Canvas canvas) {

super.onDraw(canvas);

/**中心点的x坐标*/

float centerX = (getWidth()) / 2;

/**指定圆弧的外轮廓矩形区域*/

RectF rectF = new RectF(0 + borderWidth, borderWidth, 2 * centerX - borderWidth, 2 * centerX - borderWidth);

/**【第一步】绘制整体的黄色圆弧*/

drawArcYellow(canvas, rectF);

/**【第二步】绘制当前进度的红色圆弧*/

drawArcRed(canvas, rectF);

/**【第三步】绘制当前进度的红色数字*/

drawTextNumber(canvas, centerX);

/**【第四步】绘制"步数"的红色数字*/

drawTextStepString(canvas, centerX);

}

/**

* 1.绘制总步数的黄色圆弧

*

* @param canvas 画笔

* @param rectF 参考的矩形

*/

private void drawArcYellow(Canvas canvas, RectF rectF) {

Paint paint = new Paint();

/** 默认画笔颜色,黄色 */

paint.setColor(getResources().getColor(R.color.yellow));

/** 结合处为圆弧*/

paint.setStrokeJoin(Paint.Join.ROUND);

/** 设置画笔的样式 Paint.Cap.Round ,Cap.SQUARE等分别为圆形、方形*/

paint.setStrokeCap(Paint.Cap.ROUND);

/** 设置画笔的填充样式 Paint.Style.FILL :填充内部;Paint.Style.FILL_AND_STROKE :填充内部和描边; Paint.Style.STROKE :仅描边*/

paint.setStyle(Paint.Style.STROKE);

/**抗锯齿功能*/

paint.setAntiAlias(true);

/**设置画笔宽度*/

paint.setStrokeWidth(borderWidth);

/**绘制圆弧的方法

* drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint)//画弧,

参数一是RectF对象,一个矩形区域椭圆形的界限用于定义在形状、大小、电弧,

参数二是起始角(度)在电弧的开始,圆弧起始角度,单位为度。

参数三圆弧扫过的角度,顺时针方向,单位为度,从右中间开始为零度。

参数四是如果这是true(真)的话,在绘制圆弧时将圆心包括在内,通常用来绘制扇形;如果它是false(假)这将是一个弧线,

参数五是Paint对象;

*/

canvas.drawArc(rectF, startAngle, angleLength, false, paint);

}

/**

* 2.绘制当前步数的红色圆弧

*/

private void drawArcRed(Canvas canvas, RectF rectF) {

Paint paintCurrent = new Paint();

paintCurrent.setStrokeJoin(Paint.Join.ROUND);

paintCurrent.setStrokeCap(Paint.Cap.ROUND);//圆角弧度

paintCurrent.setStyle(Paint.Style.STROKE);//设置填充样式

paintCurrent.setAntiAlias(true);//抗锯齿功能

paintCurrent.setStrokeWidth(borderWidth);//设置画笔宽度

paintCurrent.setColor(getResources().getColor(R.color.red));//设置画笔颜色

canvas.drawArc(rectF, startAngle, currentAngleLength, false, paintCurrent);

}

/**

* 3.圆环中心的步数

*/

private void drawTextNumber(Canvas canvas, float centerX) {

Paint vTextPaint = new Paint();

vTextPaint.setTextAlign(Paint.Align.CENTER);

vTextPaint.setAntiAlias(true);//抗锯齿功能

vTextPaint.setTextSize(numberTextSize);

Typeface font = Typeface.create(Typeface.SANS_SERIF, Typeface.NORMAL);

vTextPaint.setTypeface(font);//字体风格

vTextPaint.setColor(getResources().getColor(R.color.red));

Rect bounds_Number = new Rect();

vTextPaint.getTextBounds(stepNumber, 0, stepNumber.length(), bounds_Number);

canvas.drawText(stepNumber, centerX, getHeight() / 2 + bounds_Number.height() / 2, vTextPaint);

}

/**

* 4.圆环中心[步数]的文字

*/

private void drawTextStepString(Canvas canvas, float centerX) {

Paint vTextPaint = new Paint();

vTextPaint.setTextSize(dipToPx(16));

vTextPaint.setTextAlign(Paint.Align.CENTER);

vTextPaint.setAntiAlias(true);//抗锯齿功能

vTextPaint.setColor(getResources().getColor(R.color.grey));

String stepString = "步数";

Rect bounds = new Rect();

vTextPaint.getTextBounds(stepString, 0, stepString.length(), bounds);

canvas.drawText(stepString, centerX, getHeight() / 2 + bounds.height() + getFontHeight(numberTextSize), vTextPaint);

}

/**

* 获取当前步数的数字的高度

*

* @param fontSize 字体大小

* @return 字体高度

*/

public int getFontHeight(float fontSize) {

Paint paint = new Paint();

paint.setTextSize(fontSize);

Rect bounds_Number = new Rect();

paint.getTextBounds(stepNumber, 0, stepNumber.length(), bounds_Number);

return bounds_Number.height();

}

/**

* dip 转换成px

*

* @param dip

* @return

*/

private int dipToPx(float dip) {

float density = getContext().getResources().getDisplayMetrics().density;

return (int) (dip * density + 0.5f * (dip >= 0 ? 1 : -1));

}

/**

* 所走的步数进度

*

* @param totalStepNum 设置的步数

* @param currentCounts 所走步数

*/

public void setCurrentCount(int totalStepNum, int currentCounts) {

stepNumber = currentCounts + "";

setTextSize(currentCounts);

/**如果当前走的步数超过总步数则圆弧还是270度,不能成为园*/

if (currentCounts > totalStepNum) {

currentCounts = totalStepNum;

}

/**所走步数占用总共步数的百分比*/

float scale = (float) currentCounts / totalStepNum;

/**换算成弧度最后要到达的角度的长度-->弧长*/

float currentAngleLength = scale * angleLength;

/**开始执行动画*/

setAnimation(0, currentAngleLength, animationLength);

}

/**

* 为进度设置动画

* ValueAnimator是整个属性动画机制当中最核心的一个类,属性动画的运行机制是通过不断地对值进行操作来实现的,

* 而初始值和结束值之间的动画过渡就是由ValueAnimator这个类来负责计算的。

* 它的内部使用一种时间循环的机制来计算值与值之间的动画过渡,

* 我们只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,

* 那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果。

*

* @param last

* @param current

*/

private void setAnimation(float last, float current, int length) {

ValueAnimator progressAnimator = ValueAnimator.ofFloat(last, current);

progressAnimator.setDuration(length);

progressAnimator.setTarget(currentAngleLength);

progressAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

currentAngleLength = (float) animation.getAnimatedValue();

invalidate();

}

});

progressAnimator.start();

}

/**

* 设置文本大小,防止步数特别大之后放不下,将字体大小动态设置

*

* @param num

*/

public void setTextSize(int num) {

String s = String.valueOf(num);

int length = s.length();

if (length <= 4) {

numberTextSize = dipToPx(50);

} else if (length > 4 && length <= 6) {

numberTextSize = dipToPx(40);

} else if (length > 6 && length <= 8) {

numberTextSize = dipToPx(30);

} else if (length > 8) {

numberTextSize = dipToPx(25);

}

}

}

8.用法说明

xml中

android:id="@+id/sv "

android:layout_width="200dp"

android:layout_height="200dp"

android:layout_centerHorizontal="true"

android:layout_marginTop="50dp" />

Activity中

StepArcView sv = (StepArcView) findViewById(R.id.sv);

sv.setCurrentCount(7000, 1000);

以上所述是小编给大家介绍的Android 仿QQ运动步数圆弧及动画效果,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

android 自定义园动画,Android 自定View实现仿QQ运动步数圆弧及动画效果相关推荐

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

    转载请注明出处:http://blog.csdn.net/linglongxin24/article/details/52936609 [DylanAndroid的csdn博客] 在之前的Androi ...

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

    文章目录 前言 先看效果图 ![在这里插入图片描述](https://img-blog.csdnimg.cn/6e4ddec17933496ea4830fa08d8ffbe5.png?x-oss-pr ...

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

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

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

    前言 今天接着上一篇来写关于自定义View方面的东西,我是近期在学习整理这方面的知识点,所以把相关的笔记都放到这个Android自定义View的专栏里了,方便自己下次忘记的时候能回来翻翻,今天的内容是 ...

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

    项目GitHub地址 思路 固定不动的蓝色大圆弧 动画变动的红色小圆弧 中间的步数文字显示 相关的自定义属性 比如固定不动的大圆弧, 我们不能写死他的蓝色颜色属性, 要提供一个颜色的自定义属性给用户自 ...

  6. android自定义计步器形状,Android自定义View仿QQ运动步数效果

    本文实例为大家分享了Android QQ运动步数的具体代码,供大家参考,具体内容如下 今天我们实现下面这样的效果: 首先自定义属性: 自定义View代码如下: /** * Created by Mic ...

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

    自定义View学习的小记录之第一篇 自定义View学习之QQ计步器 如何实现 1.分析想要得到什么效果 2.确定自定义属性,编写attrs.xml 3.在布局中使用 4.在自定义View中获取自定义属 ...

  8. 3.Android 仿QQ运动步数进度效果 keep运动效果(从入门到巅峰)

    1.自定义控件的步骤 2.构造函数有什么用 3.自定义属性有什么用 4.初始化一些画笔放在哪里 5.onmesure()如何写 6.invalide源码分析 1.写一个类继承view或者其他控件 pu ...

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

    1. 概述   我记得QQ之前是有一个,运动步数的进度效果,今天打开QQ一看发现没有了.具体效果我也不清楚了,我就按照自己大概的印象写一下,这一期我们主要是熟悉Paint画笔的使用:    2. 效果 ...

最新文章

  1. 2021-06-082021年春季学期-信号与系统-第十五次作业-第四小题参考答案
  2. 程序员最害怕的5件事 你中招了吗?
  3. XAML概要--事件和后台代码
  4. RCP:如何移除Toolbar中的Quick Access
  5. 对if...else if...的理解
  6. XP系统下IE7访问HTTPS网站提示“此网站的安全证书有问题”的解题思路
  7. 重构wangEditor(web富文本编辑器),欢迎指正!
  8. 你真的了解开源镜像站吗?
  9. 规范第三方支付易加大竞合关系
  10. t检验怎么分析结果python_使用python 批量 配对t检验 医学 基础研究 数据分析
  11. c语言sql数据库大作业,c语言连接sql数据库.docx
  12. Golang panic: reflect: reflect.flag.mustBeAssignable using value obtained using unexported field
  13. unity 通过摄像机模拟实现小地图
  14. 粒子群算法理解+求解01背包问题
  15. 企业中流砥柱:别让企业中层缺位
  16. 中国电子标签(RFID)产业趋势研究及十四五发展规划建议报告2022-2028年版
  17. 安装RedHat Linux 7.4
  18. Python二维字典的几个小例子
  19. python爬虫,虎牙房间爬取(selenium)
  20. 使用FeignClient注解,进行远程http第三方调用

热门文章

  1. 解密古代五大美男的凄惨结局
  2. Redisson(2-1)分布式锁实现对比 VS Java的ReentrantLock之tryLock
  3. STM32驱动U盘时KILE5中#error编译不通过
  4. 云脉文档管理小程序使办公更协同
  5. Nod32升级服务器(转)
  6. 两个鸡蛋--一道Google面试题
  7. keras之权重初始化
  8. vue使用provide / inject 组合刷新页面+单独组件刷新
  9. 腹板拼接宽度_钢结构工程部件拼接一般规定
  10. fsck.ext3:unable to resolve 'LABLE=/home'