# 8.4.4 Android动画合集之属性动画-又见
## 本节引言:
上节我们对Android的属性动画进行了初步的学习,相信大家对于属性动画已经不再是 一知半解的状态了,本节我们继续来探究Android属性动画的一些更高级的用法! 依旧贴下郭神的三篇文章~
[Android属性动画完全解析(上),初识属性动画的基本用法](http://blog.csdn.net/guolin_blog/article/details/43536355)
[Android属性动画完全解析(中),ValueAnimator和ObjectAnimator的高级用法](http://blog.csdn.net/guolin_blog/article/details/43816093)
[Android属性动画完全解析(下),Interpolator和ViewPropertyAnimator的用法](http://blog.csdn.net/guolin_blog/article/details/44171115)
内容依旧是参考的上述三篇文章,好的,开始本节内容~
## 1.Evaluator自定义
### **1)Evaluator介绍**
上一节中的[8.4.3 Android动画合集之属性动画-初见](http://www.runoob.com/w3cnote/android-tutorial-valueanimator.html "8.4.3 Android动画合集之属性动画-初见"),使用动画的第一步都是:
调用ValueAnimator的**ofInt**(),**ofFloat**()或**ofObject**()静态方法创建ValueAnimator实例!
在例子中,ofInt和ofFloat我们都用到了,分别用于对浮点型和整型的数据进行动画操作!
那么**ofObject**()?初始对象和结束对象?如何过渡法?或者说这玩意怎么用?
好的,带着疑问,我们先来了解一个东西:Evaluator,在属性动画概念叨叨逼处其实我们就说到了这个东西:
![](http://www.runoob.com/wp-content/uploads/2015/11/54469594.jpg)
**用来告诉动画系统如何从初始值过渡到结束值**!好的,我们的入手点没错! 我们进去IntEvaluator的源码,看下里面写了些什么?
![](http://www.runoob.com/wp-content/uploads/2015/11/48403251.jpg)
嗯,实现了**TypeEvaluator**接口,然后重写了**evaluate()**方法,参数有三个,依次是:
* **fraction**:动画的完成度,我们根据他来计算动画的值应该是多少
* **startValue**:动画的起始值
* **endValue**:动画的结束值
**动画的值 = 初始值 + 完成度 * (结束值 - 初始值)**
同样的还有FloatEvaluator,我们想告诉系统如何从初始对象过度到结束对象,那么我们就要 自己来实现**TypeEvaluator**接口,即自定义Evaluator了,说多无益,写个例子来看看:
### **2)使用示例**
**运行效果图**:
![](http://www.runoob.com/wp-content/uploads/2015/11/10209964.jpg)
**代码实现**:
定义一个对象**Point.java**,对象中只有x,y两个属性以及get,set方法~
```
/**
* Created by Jay on 2015/11/18 0018.
*/
public class Point {
private float x;
private float y;
public Point() {
}
public Point(float x, float y) {
this.x = x;
this.y = y;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
public void setX(float x) {
this.x = x;
}
public void setY(float y) {
this.y = y;
}
}
```
接着自定义Evaluator类:**PointEvaluator.java**,实现接口重写evaluate方法~
```
/**
* Created by Jay on 2015/11/18 0018.
*/
public class PointEvaluator implements TypeEvaluator<Point>{
@Override
public Point evaluate(float fraction, Point startValue, Point endValue) {
float x = startValue.getX() + fraction * (endValue.getX() - startValue.getX());
float y = startValue.getY() + fraction * (endValue.getY() - startValue.getY());
Point point = new Point(x, y);
return point;
}
}
```
然后自定义一个View类:**AnimView.java**,很简单~
```
/**
* Created by Jay on 2015/11/18 0018.
*/
public class AnimView extends View {
public static final float RADIUS = 80.0f;
private Point currentPoint;
private Paint mPaint;
public AnimView(Context context) {
this(context, null);
}
public AnimView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public AnimView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private void init() {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.BLUE);
}
private void drawCircle(Canvas canvas){
float x = currentPoint.getX();
float y = currentPoint.getY();
canvas.drawCircle(x, y, RADIUS, mPaint);
}
private void startAnimation() {
Point startPoint = new Point(RADIUS, RADIUS);
Point endPoint = new Point(getWidth() - RADIUS, getHeight() - RADIUS);
ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentPoint = (Point) animation.getAnimatedValue();
invalidate();
}
});
anim.setDuration(3000l);
anim.start();
}
@Override
protected void onDraw(Canvas canvas) {
if (currentPoint == null) {
currentPoint = new Point(RADIUS, RADIUS);
drawCircle(canvas);
startAnimation();
} else {
drawCircle(canvas);
}
}
}
```
最后**MainActivity.java**处实例化这个View即可~
```
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new AnimView(this));
}
}
```
### **3)示例增强版**
我们上面示例的基础上加上圆移动时的颜色变化~ 这里我们另外用一个ObjectAnimator来加载颜色变化的动画,我们在View中加多个 int color来控制颜色,另外写上getColor()和setColor()的方法,我们先来自定义个Evaluator吧~
**运行效果图**:
![](http://www.runoob.com/wp-content/uploads/2015/11/65529491.jpg)
**实现代码**:
**ColorEvaluator.java**:
```
/**
* Created by Jay on 2015/11/18 0018.
*/
public class ColorEvaluator implements TypeEvaluator<Integer>{
@Override
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
int alpha = (int) (Color.alpha(startValue) + fraction *
(Color.alpha(endValue) - Color.alpha(startValue)));
int red = (int) (Color.red(startValue) + fraction *
(Color.red(endValue) - Color.red(startValue)));
int green = (int) (Color.green(startValue) + fraction *
(Color.green(endValue) - Color.green(startValue)));
int blue = (int) (Color.blue(startValue) + fraction *
(Color.blue(endValue) - Color.blue(startValue)));
return Color.argb(alpha, red, green, blue);
}
}
```
然后自定义View那里加个color,get和set方法;创建一个ObjectAnimator, 和AnimatorSet,接着把动画组合到一起就到,这里就加点东西而已,怕读者有问题, 直接另外建个View吧~
**AnimView2.java**:
```
/**
* Created by Jay on 2015/11/18 0018.
*/
public class AnimView2 extends View {
public static final float RADIUS = 80.0f;
private Point currentPoint;
private Paint mPaint;
private int mColor;
public AnimView2(Context context) {
this(context, null);
}
public AnimView2(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public AnimView2(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private void init() {
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.BLUE);
}
private void drawCircle(Canvas canvas){
float x = currentPoint.getX();
float y = currentPoint.getY();
canvas.drawCircle(x, y, RADIUS, mPaint);
}
private void startAnimation() {
Point startPoint = new Point(RADIUS, RADIUS);
Point endPoint = new Point(getWidth() - RADIUS, getHeight() - RADIUS);
ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentPoint = (Point) animation.getAnimatedValue();
invalidate();
}
});
ObjectAnimator objectAnimator = ObjectAnimator.ofObject(this, "color", new ColorEvaluator(),
Color.BLUE, Color.RED);
//动画集合将前面两个动画加到一起,with同时播放
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(anim).with(objectAnimator);
animatorSet.setStartDelay(1000l);
animatorSet.setDuration(3000l);
animatorSet.start();
}
@Override
protected void onDraw(Canvas canvas) {
if (currentPoint == null) {
currentPoint = new Point(RADIUS, RADIUS);
drawCircle(canvas);
startAnimation();
} else {
drawCircle(canvas);
}
}
//color的get和set方法~
public int getColor() {
return mColor;
}
public void setColor(int color) {
mColor = color;
mPaint.setColor(color);
invalidate();
}
}
```
然后MainActivity,setContentView那里把AnimView改成AnimView2就好~
## 2.Interpolator(补间器)
嗯,在讲补间动画的时候我们就讲过这个东东了~不知道你还有印象没?
![](http://www.runoob.com/wp-content/uploads/2015/11/73854084.jpg)
上面的补间器补间动画和属性动画都可用,而且补间动画还新增了一个**TimeInterpolator**接口 该接口是用于兼容之前的Interpolator的,这使得所有过去的Interpolator实现类都可以直接拿过来 放到属性动画当中使用!我们可以调用动画对象的setInterpolator()方法设置不同的Interpolator! 我们先该点东西,让小球从屏幕正中央的顶部掉落到底部~ 然后我们会我们为我们的集合动画调用下述语句: **animatorSet.setInterpolator(new AccelerateInterpolator(2f));** 括号里的值用于控制加速度~
**运行效果**:
![](http://www.runoob.com/wp-content/uploads/2015/11/6420198.jpg)
好像有点不和常理,正常应该是会弹起来的吧,我们换成**BounceInterpolator**试试~
![](http://www.runoob.com/wp-content/uploads/2015/11/42165604.jpg)
嘿嘿,效果蛮赞的,当然还有N多个系统提供好的Interpolator,大家可以自己一一尝试,这里就 不慢慢跟大家纠结了~
下面我们来看看:
### **1)Interpolator的内部实现机制**
我们先到TimeInterpolator接口的源码,发现这里只有一个**getInterpolation**()方法;
![](http://www.runoob.com/wp-content/uploads/2015/11/6378219.jpg)
**简单的解释**: getInterpolation()方法中接收一个input参数,这个参数的值会随着动画的运行而不断变化, 不过它的变化是非常有规律的,就是根据设定的动画时长匀速增加,变化范围是0到1。 也就是说当动画一开始的时候input的值是0,到动画结束的时候input的值是1,而中间的值则 是随着动画运行的时长在0到1之间变化的。
这里的**input**值决定了我们**TypeEvaluator**接口里的**fraction**的值。 input的值是由系统经过计算后传入到getInterpolation()方法中的,然后我们可以自己实现 **getInterpolation**()方法中的算法,根据input的值来计算出一个返回值,而这个返回值就是fraction了。
我们可以看看**LinearInterpolator**里的代码:
![](http://www.runoob.com/wp-content/uploads/2015/11/53510297.jpg)
这里没有处理过直接返回input值,即fraction的值就是等于input的值,这就是匀速运动的 Interpolator的实现方式!其实无非就是算法不同,这就涉及到一些数学的东西了,又一次 体会到数学的重要性了,这里再贴个**BounceInterpolator**的源码吧:
![](http://www.runoob.com/wp-content/uploads/2015/11/43642406.jpg)
别问我这里的算法,我也不知道哈,我们再找个容易理解点的:**AccelerateDecelerateInterpolator**
![](http://www.runoob.com/wp-content/uploads/2015/11/80592279.jpg)
这个Interpolator是先加速后减速效果的: **(float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f** 的算法理解:
解:由input的取值范围为[0,1],可以得出cos中的值的取值范围为[π,2π],对应的值为-1和1; 再用这个值来除以2加上0.5之后,getInterpolation()方法最终返回的结果值范围还是[0,1], 对应的曲线图如下:
![](http://www.runoob.com/wp-content/uploads/2015/11/Center)
所以是一个先加速后减速的过程!
嗯,学渣没法玩了...![](http://www.runoob.com/wp-content/uploads/2015/11/90823139.jpg),上面全是郭大叔文章里搬过来的...我想静静...
### **2)自定义Interpolator**
好吧,还是等会儿再忧伤吧,写个自定义的Interpolator示例先: 非常简单,实现TimeInterpolator接口,重写getInterpolation方法
**示例代码如下**
```
private class DecelerateAccelerateInterpolator implements TimeInterpolator {
@Override
public float getInterpolation(float input) {
if (input < 0.5) {
return (float) (Math.sin(input * Math.PI) / 2);
} else {
return 1 - (float) (Math.sin(input * Math.PI) / 2);
}
}
}
```
调用setInterpolator(new DecelerateAccelerateInterpolator())设置下即可~ 限于篇幅就不贴图了~
## 3.ViewPropertyAnimator
3.1后系统当中附增的一个新的功能,为View的动画操作提供一种更加便捷的用法! 假如是以前,让一个TextView从正常状态变成透明状态,会这样写:
```
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 0f);
animator.start();
```
而使用ViewPropertyAnimator来实现同样的效果则显得更加易懂:
```
textview.animate().alpha(0f);
```
还支持**连缀用法**,组合多个动画,设定时长,设置Interpolator等~
```
textview.animate().x(500).y(500).setDuration(5000)
.setInterpolator(new BounceInterpolator());
```
用法很简单,使用的时候查下文档就好~,另外下面有几个细节的地方要注意一下!
* 整个ViewPropertyAnimator的功能都是建立在View类新增的animate()方法之上的, 这个方法会创建并返回一个ViewPropertyAnimator的实例,之后的调用的所有方法, 设置的所有属性都是通过这个实例完成的。
* 使用ViewPropertyAnimator将**动画定义完成之后**,动画就会**自动启动**。 并且这个机制对于组合动画也同样有效,只要我们不断地连缀新的方法, 那么动画就不会立刻执行,等到所有在ViewPropertyAnimator上设置的方法都执行完毕后, 动画就会自动启动。当然如果不想使用这一默认机制的话,我们也可以显式地调用 **start**()方法来启动动画。
* ViewPropertyAnimator的所有接口都是使用连缀的语法来设计的,每个方法的返回值都是 它**自身的实例**,因此调用完一个方法之后可以直接连缀调用它的另一个方法,这样把所有的 功能都串接起来,我们甚至可以仅通过一行代码就完成任意复杂度的动画功能。
## 4.本节示例代码下载
[AnimatorDemo3.zip](http://static.runoob.com/download/AnimatorDemo3.zip)
在Github上找到一个动画合集的项目,很多动画效果都有,下面贴下地址:
[BaseAnimation 动画合集](https://github.com/z56402344/BaseAnimation)
想研究各种动画是如何实现的可自行查看源码~
## 本节小结
> 嗯,本节我们讲了一些稍微高深一点的东西Evaluator啊,Interpolator啊,还有 ViewPropertyAnimator,是不是又拓展了大家的见识~本节也是Android基础入门绘图 与的最后一小节了,如果大家把这一章节的内容都掌握了,再去学自定义控件, 或者看别人写的自定义控件,应该不会再那么地不知道从何入手,遇到一堆新面孔了吧!
>
> 嗯,还是谢谢郭神的文章,属性动画部分的内容很都是直接在郭神那里搬过来的 ![](http://www.runoob.com/wp-content/uploads/2015/11/95631595.jpg)嘿嘿~本节就到这里,谢谢~
>
> PS:后面的示意图换模拟器是因为的N5秀逗了...
- 1.0 Android基础入门教程
- 1.0.1 2015年最新Android基础入门教程目录
- 1.1 背景相关与系统架构分析
- 1.2 开发环境搭建
- 1.2.1 使用Eclipse + ADT + SDK开发Android APP
- 1.2.2 使用Android Studio开发Android APP
- 1.3 SDK更新不了问题解决
- 1.4 Genymotion模拟器安装
- 1.5.1 Git使用教程之本地仓库的基本操作
- 1.5.2 Git之使用GitHub搭建远程仓库
- 1.6 .9(九妹)图片怎么玩
- 1.7 界面原型设计
- 1.8 工程相关解析(各种文件,资源访问)
- 1.9 Android程序签名打包
- 1.11 反编译APK获取代码&资源
- 2.1 View与ViewGroup的概念
- 2.2.1 LinearLayout(线性布局)
- 2.2.2 RelativeLayout(相对布局)
- 2.2.3 TableLayout(表格布局)
- 2.2.4 FrameLayout(帧布局)
- 2.2.5 GridLayout(网格布局)
- 2.2.6 AbsoluteLayout(绝对布局)
- 2.3.1 TextView(文本框)详解
- 2.3.2 EditText(输入框)详解
- 2.3.3 Button(按钮)与ImageButton(图像按钮)
- 2.3.4 ImageView(图像视图)
- 2.3.5.RadioButton(单选按钮)&Checkbox(复选框)
- 2.3.6 开关按钮ToggleButton和开关Switch
- 2.3.7 ProgressBar(进度条)
- 2.3.8 SeekBar(拖动条)
- 2.3.9 RatingBar(星级评分条)
- 2.4.1 ScrollView(滚动条)
- 2.4.2 Date & Time组件(上)
- 2.4.3 Date & Time组件(下)
- 2.4.4 Adapter基础讲解
- 2.4.5 ListView简单实用
- 2.4.6 BaseAdapter优化
- 2.4.7ListView的焦点问题
- 2.4.8 ListView之checkbox错位问题解决
- 2.4.9 ListView的数据更新问题
- 2.5.0 构建一个可复用的自定义BaseAdapter
- 2.5.1 ListView Item多布局的实现
- 2.5.2 GridView(网格视图)的基本使用
- 2.5.3 Spinner(列表选项框)的基本使用
- 2.5.4 AutoCompleteTextView(自动完成文本框)的基本使用
- 2.5.5 ExpandableListView(可折叠列表)的基本使用
- 2.5.6 ViewFlipper(翻转视图)的基本使用
- 2.5.7 Toast(吐司)的基本使用
- 2.5.8 Notification(状态栏通知)详解
- 2.5.9 AlertDialog(对话框)详解
- 2.6.0 其他几种常用对话框基本使用
- 2.6.1 PopupWindow(悬浮框)的基本使用
- 2.6.2 菜单(Menu)
- 2.6.3 ViewPager的简单使用
- 2.6.4 DrawerLayout(官方侧滑菜单)的简单使用
- 3.1.1 基于监听的事件处理机制
- 3.2 基于回调的事件处理机制
- 3.3 Handler消息传递机制浅析
- 3.4 TouchListener PK OnTouchEvent + 多点触碰
- 3.5 监听EditText的内容变化
- 3.6 响应系统设置的事件(Configuration类)
- 3.7 AnsyncTask异步任务
- 3.8 Gestures(手势)
- 4.1.1 Activity初学乍练
- 4.1.2 Activity初窥门径
- 4.1.3 Activity登堂入室
- 4.2.1 Service初涉
- 4.2.2 Service进阶
- 4.2.3 Service精通
- 4.3.1 BroadcastReceiver牛刀小试
- 4.3.2 BroadcastReceiver庖丁解牛
- 4.4.2 ContentProvider再探——Document Provider
- 4.5.1 Intent的基本使用
- 4.5.2 Intent之复杂数据的传递
- 5.1 Fragment基本概述
- 5.2.1 Fragment实例精讲——底部导航栏的实现(方法1)
- 5.2.2 Fragment实例精讲——底部导航栏的实现(方法2)
- 5.2.3 Fragment实例精讲——底部导航栏的实现(方法3)
- 5.2.4 Fragment实例精讲——底部导航栏+ViewPager滑动切换页面
- 5.2.5 Fragment实例精讲——新闻(购物)类App列表Fragment的简单实现
- 6.1 数据存储与访问之——文件存储读写
- 6.2 数据存储与访问之——SharedPreferences保存用户偏好参数
- 6.3.1 数据存储与访问之——初见SQLite数据库
- 6.3.2 数据存储与访问之——又见SQLite数据库
- 7.1.1 Android网络编程要学的东西与Http协议学习
- 7.1.2 Android Http请求头与响应头的学习
- 7.1.3 Android HTTP请求方式:HttpURLConnection
- 7.1.4 Android HTTP请求方式:HttpClient
- 7.2.1 Android XML数据解析
- 7.2.2 Android JSON数据解析
- 7.3.1 Android 文件上传
- 7.3.2 Android 文件下载(1)
- 7.3.3 Android 文件下载(2)
- 7.4 Android 调用 WebService
- 7.5.1 WebView(网页视图)基本用法
- 7.5.2 WebView和JavaScrip交互基础
- 7.5.3 Android 4.4后WebView的一些注意事项
- 7.5.4 WebView文件下载
- 7.5.5 WebView缓存问题
- 7.5.6 WebView处理网页返回的错误码信息
- 7.6.1 Socket学习网络基础准备
- 7.6.2 基于TCP协议的Socket通信(1)
- 7.6.3 基于TCP协议的Socket通信(2)
- 7.6.4 基于UDP协议的Socket通信
- 8.1.1 Android中的13种Drawable小结 Part 1
- 8.1.2 Android中的13种Drawable小结 Part 2
- 8.1.3 Android中的13种Drawable小结 Part 3
- 8.2.1 Bitmap(位图)全解析 Part 1
- 8.2.2 Bitmap引起的OOM问题
- 8.3.1 三个绘图工具类详解
- 8.3.2 绘图类实战示例
- 8.3.3 Paint API之—— MaskFilter(面具)
- 8.3.4 Paint API之—— Xfermode与PorterDuff详解(一)
- 8.3.5 Paint API之—— Xfermode与PorterDuff详解(二)
- 8.3.6 Paint API之—— Xfermode与PorterDuff详解(三)
- 8.3.7 Paint API之—— Xfermode与PorterDuff详解(四)
- 8.3.8 Paint API之—— Xfermode与PorterDuff详解(五)
- 8.3.9 Paint API之—— ColorFilter(颜色过滤器)(1/3)
- 8.3.10 Paint API之—— ColorFilter(颜色过滤器)(2-3)
- 8.3.11 Paint API之—— ColorFilter(颜色过滤器)(3-3)
- 8.3.12 Paint API之—— PathEffect(路径效果)
- 8.3.13 Paint API之—— Shader(图像渲染)
- 8.3.14 Paint几个枚举/常量值以及ShadowLayer阴影效果
- 8.3.15 Paint API之——Typeface(字型)
- 8.3.16 Canvas API详解(Part 1)
- 8.3.17 Canvas API详解(Part 2)剪切方法合集
- 8.3.18 Canvas API详解(Part 3)Matrix和drawBitmapMash
- 8.4.1 Android动画合集之帧动画
- 8.4.2 Android动画合集之补间动画
- 8.4.3 Android动画合集之属性动画-初见
- 8.4.4 Android动画合集之属性动画-又见
- 9.1 使用SoundPool播放音效(Duang~)
- 9.2 MediaPlayer播放音频与视频
- 9.3 使用Camera拍照
- 9.4 使用MediaRecord录音
- 10.1 TelephonyManager(电话管理器)
- 10.2 SmsManager(短信管理器)
- 10.3 AudioManager(音频管理器)
- 10.4 Vibrator(振动器)
- 10.5 AlarmManager(闹钟服务)
- 10.6 PowerManager(电源服务)
- 10.7 WindowManager(窗口管理服务)
- 10.8 LayoutInflater(布局服务)
- 10.9 WallpaperManager(壁纸管理器)
- 10.10 传感器专题(1)——相关介绍
- 10.11 传感器专题(2)——方向传感器
- 10.12 传感器专题(3)——加速度/陀螺仪传感器
- 10.12 传感器专题(4)——其他传感器了解
- 10.14 Android GPS初涉
- 11.0《2015最新Android基础入门教程》完结散花~