android 自定义园动画,Android 自定View实现仿QQ运动步数圆弧及动画效果
在之前的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运动步数圆弧及动画效果相关推荐
- 【Android自定义View实战】之仿QQ运动步数圆弧及动画,Dylan计步中的控件StepArcView
转载请注明出处:http://blog.csdn.net/linglongxin24/article/details/52936609 [DylanAndroid的csdn博客] 在之前的Androi ...
- Android自定义View之仿QQ运动步数进度效果
文章目录 前言 先看效果图 ![在这里插入图片描述](https://img-blog.csdnimg.cn/6e4ddec17933496ea4830fa08d8ffbe5.png?x-oss-pr ...
- android 自定义view实现仿QQ运动步数进度效果
最近公司在策划一个新的项目,原型还没出来,再说这公司人都要走没了,估计又要找工作了,所以必须要学习,争取每个写个关于自定义view方面的,这样几个月积累下来,也能学习到东西,今天就带来简单的效果,就是 ...
- 自定义View之仿QQ运动步数进度效果
前言 今天接着上一篇来写关于自定义View方面的东西,我是近期在学习整理这方面的知识点,所以把相关的笔记都放到这个Android自定义View的专栏里了,方便自己下次忘记的时候能回来翻翻,今天的内容是 ...
- 自定义View | 仿QQ运动步数进度效果
项目GitHub地址 思路 固定不动的蓝色大圆弧 动画变动的红色小圆弧 中间的步数文字显示 相关的自定义属性 比如固定不动的大圆弧, 我们不能写死他的蓝色颜色属性, 要提供一个颜色的自定义属性给用户自 ...
- android自定义计步器形状,Android自定义View仿QQ运动步数效果
本文实例为大家分享了Android QQ运动步数的具体代码,供大家参考,具体内容如下 今天我们实现下面这样的效果: 首先自定义属性: 自定义View代码如下: /** * Created by Mic ...
- 自定义View学习之仿QQ运动步数进度效果
自定义View学习的小记录之第一篇 自定义View学习之QQ计步器 如何实现 1.分析想要得到什么效果 2.确定自定义属性,编写attrs.xml 3.在布局中使用 4.在自定义View中获取自定义属 ...
- 3.Android 仿QQ运动步数进度效果 keep运动效果(从入门到巅峰)
1.自定义控件的步骤 2.构造函数有什么用 3.自定义属性有什么用 4.初始化一些画笔放在哪里 5.onmesure()如何写 6.invalide源码分析 1.写一个类继承view或者其他控件 pu ...
- 自定义View 仿QQ运动步数进度效果
1. 概述 我记得QQ之前是有一个,运动步数的进度效果,今天打开QQ一看发现没有了.具体效果我也不清楚了,我就按照自己大概的印象写一下,这一期我们主要是熟悉Paint画笔的使用: 2. 效果 ...
最新文章
- 2021-06-082021年春季学期-信号与系统-第十五次作业-第四小题参考答案
- 程序员最害怕的5件事 你中招了吗?
- XAML概要--事件和后台代码
- RCP:如何移除Toolbar中的Quick Access
- 对if...else if...的理解
- XP系统下IE7访问HTTPS网站提示“此网站的安全证书有问题”的解题思路
- 重构wangEditor(web富文本编辑器),欢迎指正!
- 你真的了解开源镜像站吗?
- 规范第三方支付易加大竞合关系
- t检验怎么分析结果python_使用python 批量 配对t检验 医学 基础研究 数据分析
- c语言sql数据库大作业,c语言连接sql数据库.docx
- Golang panic: reflect: reflect.flag.mustBeAssignable using value obtained using unexported field
- unity 通过摄像机模拟实现小地图
- 粒子群算法理解+求解01背包问题
- 企业中流砥柱:别让企业中层缺位
- 中国电子标签(RFID)产业趋势研究及十四五发展规划建议报告2022-2028年版
- 安装RedHat Linux 7.4
- Python二维字典的几个小例子
- python爬虫,虎牙房间爬取(selenium)
- 使用FeignClient注解,进行远程http第三方调用