近期项目中需要使用到一种类似手机电池充电进度的动画效果,以前没学属性动画的时候,是用图片+定时器的方式来完成的,最近一直在学习动画这一块,再加上复习一下自定义view的相关知识点,所以打算用属性动画和自定义view的方式来完成这个功能,将它开源出来,供有需要的人了解一下相关的内容。

本次实现的功能类似下面的效果:

接下来便详细解析一下如何完成这个功能,了解其中的原理,这样就能举一反三,实现其他类似的动画效果了。

详细代码请看大屏幕

https://github.com/crazyandcoder/ChargeProgress

图形解析

一般,我们自定义view时,是将该view进行化解,分成一个一个小部分,然后在重叠起来进行绘制,对于这个项目,也是按照相同的步骤进行。我们用Word来简单解析一下该动画所包含的基本结构。

对于这个充电进度view,我将它分成了ABCD四个部分,下面来详细说明各个部分的组成。

A部分

对于A而言,它是位于整个view的顶部,居中显示,是一个圆角矩形。

B部分

对于B而言,它是整个view的重要组成部分,包含C和D两部分,其中B主要属性就是背景色的设置。

C部分

对于C而言,C就是每一个进度的样式,显示的是未完成的进度条样式。

D部分

对于D而言,它跟C是一样的,只不过是已经完成的进度样式,区别在于颜色的不一样。

其实,这个进度view图形结构还是比较简单的,只是一些简单的矩形,组合而成,因此对于以上的分析,我们轻易的得出一些重要的属性。

对于以上属性,我们在自定义view的时候需要在xml文件中进行设置,如果没有设置的话,我们给出一个默认。然后我们在代码中进行获取这些属性值。

//边界宽度

private float border_width;

//item个数

private int item_count;

//边界宽度

private float item_width;

//边界高度

private float item_height;

//view内部的进度前景色

private int item_charging_src;

//view内部的进度背景色

private int item_charging_background;

//view背景色

private int background;

//

private int border_color;

//圆角半径

private float border_cornor_radius;

//获取xml中设定的属性值

TypedArray array = mContext.obtainStyledAttributes(attrs, R.styleable.charging_progress);

border_width = array.getDimension(R.styleable.charging_progress_cgv_border_width, dp2px(2));

item_height = array.getDimension(R.styleable.charging_progress_cgv_item_height, dp2px(10));

item_width = array.getDimension(R.styleable.charging_progress_cgv_item_width, dp2px(20));

item_charging_src = array.getColor(R.styleable.charging_progress_cgv_item_charging_src, 0xffffea00);

item_charging_background = array.getColor(R.styleable.charging_progress_cgv_item_charging_background, 0xff544645);

background = array.getColor(R.styleable.charging_progress_cgv_background, 0xff463938);

border_color = array.getColor(R.styleable.charging_progress_cgv_border_color, 0xffb49d7c);

border_cornor_radius = array.getDimension(R.styleable.charging_progress_cgv_border_cornor_radius, dp2px(2));

item_count = array.getInt(R.styleable.charging_progress_cgv_item_count, 10);

array.recycle();

已经获取了自定义属性的值,那么接下来,我们就来具体绘制这些组合图形。

对于一个自定义view,首先要做的就是测量view的大小,而本项目中view的宽度和高度,宽度是好计算的,我们设置view的宽度等于item_widht 乘以2 。但是对于高度的话,因为我们设置了progress的级数,也就是item_count,也设置了item的高度和宽度,所以对于高度,我们可以通过计算item_count 乘以 item_height,再加上间隔数和顶部矩形的就是整个view的高度。同时,我们设定,顶部矩形的高度等于item_height,宽度等于item_widht的一半,中间间隔等于item_height 除以2

/**

* 测量view的宽和高,

*

*@param widthMeasureSpec

*@param heightMeasureSpec

*/

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

//总间隔数=(item_count+1) 乘以间隔高度(间隔高度等于item_height的一半)

//总数=item_count 乘以 item_height + 总间隔数 + 顶部一个矩形(高度等于item的高度,宽度等于item的宽度的一半)

mHeight = (int) (item_count * item_height + (item_count + 1) * item_height / 2 + item_height);

mWidth = (int) (2 * item_width);

setMeasuredDimension(mWidth, mHeight);

}

有了上面的设置,接下来我们就可以按部就班的画图了。

对于坐标中心点是设定在左上角,也就是(0,0)处。

画顶部矩形

知道了坐标系的原点,那么顶部矩形的坐标就可以计算了。

首先设置画笔。

mPaint.setStyle(Paint.Style.STROKE);

mPaint.setStrokeWidth(border_width);

mPaint.setColor((border_color));

由于顶部矩形的width等于item_widht的一半,所以它的width等于整个view的width的1/6,

int left = mWidth * 3 / 8;

int top = 0;

int right = 5 * mWidth / 8;

int bottom = (int) item_height / 2;

//顶部的矩形

RectF topRect = new RectF(left, top, right, bottom);

canvas.drawRoundRect(topRect, border_cornor_radius, border_cornor_radius, mPaint);

接下来绘制底部的矩形,也就是包含进度item的矩形

//总的进度背景

RectF border = new RectF(0, bottom, mWidth, mHeight);

canvas.drawRoundRect(border, border_cornor_radius, border_cornor_radius, mPaint);

接下来绘制每个item的矩形,对于每个item的坐标,实际上是有规律可循的。

//绘制所有的进度

for (int i = 1; i <= item_count; i++) {

mPaint.setStyle(Paint.Style.FILL);

mPaint.setColor((item_charging_background));

RectF backRect = new RectF(mWidth / 4,

(i + 1) * item_height / 2 + (i - 1) * item_height,

3 * mWidth / 4,

item_height / 2 + i * (3 * item_height / 2));

canvas.drawRoundRect(backRect, border_cornor_radius, border_cornor_radius, mPaint);

}

绘制动画

对于交流动画,就是从进度0到100的动画显示,依次显示。其实也是对于坐标的计算而已。接下来最终要的功能就是动画的使用了,我们使用的是属性动画呢?因为,常规的动画它不支持啊,很简单。

对于Android属性动画的学习,可以查看这篇文章,稍微了解一下。《Android动画了解》

1、交流动画

/**

* 绘制交流动画

*

*@param canvas

*/

private void drawACAnimaiton(Canvas canvas) {

int j = getProgress() / item_count;

//已经充好的进度

for (int i = item_count; i >= (item_count - j); i--) {

RectF backRect = new RectF(mWidth / 4,

(i + 1) * item_height / 2 + (i - 1) * item_height,

3 * mWidth / 4,

item_height / 2 + i * (3 * item_height / 2));

canvas.drawRoundRect(backRect, border_cornor_radius, border_cornor_radius, mPaint);

mPaint.setStyle(Paint.Style.FILL);

mPaint.setColor(item_charging_src);

canvas.drawRoundRect(backRect, border_cornor_radius, border_cornor_radius, mPaint);

}

}

我们首先获取当前的进度,然后依次给它填充背景,这就是已完成的进度表示。

然后使用动画即可,我们设置进度为100,也就是充满,然后设置动画时间是10秒钟,对于下面的动画执行原理是什么呢?其实很简单,获取当前的进度,然后从0开始,依次绘制进度,知道绘制的进度为100就是总的进度,最后再循环执行动画即可。

/**

* 设置交流动画

*/

public void setACAnimation() {

chargeType = AC;

animAC = ObjectAnimator.ofInt(this, "progress", 100);

animAC.setDuration(10 * 1000);

animAC.setInterpolator(new LinearInterpolator());

animAC.setRepeatCount(ValueAnimator.INFINITE);

animAC.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

invalidate();

}

});

animAC.start();

}

2、直流动画

对于直流动画就稍微比较复杂了。当我们设置了进度后,需要我们预先绘制已完成的进度,然后在下一个进度进行闪烁表示动画,那么该如何完成呢?

首先看绘制代码:

/**

* 直流动画

*

*@param canvas

*/

private void drawDCAniamtion(Canvas canvas) {

int j = getProgress() / item_count;

//已经充好的进度

for (int i = item_count; i > (item_count - j); i--) {

RectF backRect = new RectF(mWidth / 4,

(i + 1) * item_height / 2 + (i - 1) * item_height,

3 * mWidth / 4,

item_height / 2 + i * (3 * item_height / 2));

canvas.drawRoundRect(backRect, border_cornor_radius, border_cornor_radius, mPaint);

mPaint.setStyle(Paint.Style.FILL);

mPaint.setColor(item_charging_src);

canvas.drawRoundRect(backRect, border_cornor_radius, border_cornor_radius, mPaint);

}

//下一个进度,隐藏和显示交替执行动画

int i = item_count - j;

if (i > 0) {

RectF backRect = new RectF(mWidth / 4,

(i + 1) * item_height / 2 + (i - 1) * item_height,

3 * mWidth / 4,

item_height / 2 + i * (3 * item_height / 2));

mPaint.setStyle(Paint.Style.FILL);

if (show) {

mPaint.setColor((item_charging_src));

} else {

mPaint.setColor((item_charging_background));

}

canvas.drawRoundRect(backRect, border_cornor_radius, border_cornor_radius, mPaint);

}

}

首先绘制已完成的进度,然后在绘制闪烁的部分。

/**

* 直流动画

*

*@param progress

*/

public void setDCAnimation(final int progress) {

chargeType = DC;

animatorDC = ValueAnimator.ofFloat(0, 1);

animatorDC.setInterpolator(new LinearInterpolator());

animatorDC.setDuration(1000);

animatorDC.setRepeatCount(-1);

animatorDC.setRepeatMode(ValueAnimator.RESTART);

animatorDC.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

@Override

public void onAnimationUpdate(ValueAnimator animation) {

float value = (float) animation.getAnimatedValue();

if (value > 0.5) {

show = true;

} else {

show = false;

}

setProgress(progress);

}

});

animatorDC.start();

}

到这里,就很明了了。对于直流动画,我们使用属性动画中这个ValueAnimator类,它的意思就是从0到1平滑的过渡,在设定的时间内。我们的原理是当达到0.5以上后就设定灰色进度,当小于0.5的话就设置亮色进度,然后在刷新一下view即可。

以上便是主要的原理,对于源码,可以访问《ChargeProgress》。

关于作者:

1. http://www.jianshu.com/users/18281bdb07ce/latest_articles

2. 博客 http://crazyandcoder.github.io/

3. github https://github.com/crazyandcoder

4. 开源中国 https://my.oschina.net/crazyandcoder/blog

android+属性动画+高度,android 自定义view+属性动画实现充电进度条相关推荐

  1. Android 自定义View实现环形带刻度的进度条

    本篇文章讲的是自定义View实现环形带刻度的进度条.和往常一样,主要还是想总结一下自定义View实现环形带刻度的进度条的开发过程以及一些需要注意的地方. 按照惯例,我们先来看看效果图 一.我们如何来实 ...

  2. 精通Android自定义View(十二)绘制圆形进度条

    1 绘图基础简析 1 精通Android自定义View(一)View的绘制流程简述 2 精通Android自定义View(二)View绘制三部曲 3 精通Android自定义View(三)View绘制 ...

  3. android 自定义view如何控制view的高度_Android自定义View属性动画

    属性动画 DEMO地址:https://github.com/chaozhouzhang/CustomProgressView 1.值动画 ValueAnimator 值动画具体实现步骤: /** * ...

  4. android 自定义音乐圆形进度条,Android自定义View实现音频播放圆形进度条

    本篇文章介绍自定义View配合属性动画来实现如下的效果 实现思路如下: 根据播放按钮的图片大小计算出圆形进度条的大小 根据音频的时间长度计算出圆形进度条绘制的弧度 通过Handler刷新界面来更新圆形 ...

  5. 自定义View之王者荣耀等级进度条

    Demo效果 这里用王者荣耀的等级做了一个demo 实现思路 由进度条想到ProgressBar,继承自ProgressBar,可以在onDraw()中通过getProgress()和getMax() ...

  6. android自定义控件是一个 内部类 如何在xml中引用,android 自定义view属性

    android 自定义view属性 一个完美的自定义控件也可以添加xml来配置属性和风格.要实现这一点,可按照下列步骤来做: 1) 添加自定义属性到xml文件中 2) 在xml的中,指定属性的值 3) ...

  7. Carson带你学Android:源码解析自定义View Draw过程

    前言 自定义View是Android开发者必须了解的基础 网上有大量关于自定义View原理的文章,但存在一些问题:内容不全.思路不清晰.无源码分析.简单问题复杂化 等 今天,我将全面总结自定义View ...

  8. Android 高手进阶之自定义View,自定义属性(带进度的圆形进度条)

    转载请注明地址:http://blog.csdn.net/xiaanming/article/details/10298163 很多的时候,系统自带的View满足不了我们功能的需求,那么我们就需要自己 ...

  9. Android软件开发之盘点自定义View界面大合集(二)

    Android软件开发之盘点自定义View界面大合集(二) - 雨松MOMO的程序世界 - 51CTO技术博客 雨松MOMO带大家盘点Android 中的自定义View界面的绘制 今天我用自己写的一个 ...

最新文章

  1. 用AI创造AI,人工智能无代码时代来临
  2. 日志切割清理工具 Log-Cutter
  3. java 什么时候进行垃圾回收_Java中垃圾回收有什么目的?什么时候进行垃圾回收?...
  4. mysql事务隔离级别与锁_mysql事务隔离级别与锁
  5. Datatables 给行绑定选中事件
  6. c++ stl stack_C ++ STL中的stack :: top()函数
  7. C ++ 指针 | 指针的详细概念和使用_1
  8. Vue之单文件组件和脚手架
  9. JAVA基础系列:Arrays.binarySearch二分查找
  10. [链表]同时遍历两个链表
  11. 所有子模块都要执行的checkstyle检查
  12. linux服务器启动ftp连接
  13. 计算机辅助三维参数化设计是什么,滚子链轮的计算机辅助三维参数化设计.pdf...
  14. keyword can not be an expression
  15. Win10:文件夹取消隐藏选项为灰色,无法勾选
  16. 关于如何设计网站首页
  17. JavaScript的通用库与动画特效
  18. linux进程命令at,Linux进程管理命令之sa/at/atq。
  19. 职场语录:新人,没人会告诉你的职场潜规则
  20. Unity鼠标拖拽旋转拉远拉近场景

热门文章

  1. freebsd php 编译 mysql sql2005_[伊达原创]FreeBSD8.0源码编译安装MYSQL5 APACHE2.2 PHP5.3.2
  2. Mac item2 配色,大小写敏感及常用快捷键
  3. 基于MS的氢键分析脚本介绍
  4. PROE CREO 各类3D模型图档大全-8.2G
  5. 【少样本图像生成】Towards Faster And Stabilized GAN training for high-fidelity few-shot image synthesis
  6. 计算机网络 5 - 链路层
  7. 一个简单的保护视力的软件
  8. Div+CSS网页设计(HTML5)
  9. 10天内我国痛失20位两院院士!原中科院副院长王佛松逝世,享年89岁
  10. 西南科技大学计算机专业全国排名,西南科技大学为什么在全国大学排名很低?...