Android动画知识详细总结

在Android中,动画可以分为三种,分别是补间动画(View Animation)、属性动画(Property Animation)以及帧动画(Drawable Animation)。

一、补间动画 (View Animation )
View Animation 相对简单,不过只能支持简单的缩放、平移、旋转、透明度基本的动画,且
有一定的局限性。比如:你希望 View 有一个颜色的切换动画;你希望可以使用 3D 旋转动
画;你希望当动画停止时,View 的位置就是当前的位置;这些 View Animation 都无法做到。
简单来说,补间动画只能用来 View。
它有四种典型的变换效果,分别是:
(1)平移动画
(2)缩放动画
(3)旋转动画
(4)透明度动画
这四种动画效果可以通过 java 代码的方式动态的创建,也可以通过 xml 文件来创建。

1.  通过java代码的创建方式:

1.1 平移动画
平移动画是通过 TranslateAnimation 类来实现的,常用的构造函数有以下两个:
(1)public TranslateAnimation(float fromXDelta, float toXDelta, float fromYDelta, float
toYDelta) {
}
(2)public TranslateAnimation(int fromXType, float fromXValue, int toXType, float toXValue,
int fromYType, float fromYValue, int toYType, float toYValue) {
}
先说首个构造函数,参数 fromXDelta、toXDelta 代表 x 方向平移的起始值和结束值,单位为
像素,若 toXDelta 减 fromXDelta 大于 0,则 View 右移,否则左移。fromYDelta、toYDelta 是
同样的道理,差值大于 0View 下移,否则上移。
要实现一个 View 右移 100 像素可以这么做:
TranslateAnimation translateAnimation = new TranslateAnimation(0f, 0f, 0f, 100f);
translateAnimation.setDuration(2000);//动画的持续时间,单位毫秒
translateAnimation.setFillAfter(true);//参数为 true 表示动画结束后 View 停留在结束为止
view.startAnimation(translateAnimation);//开始动画
再看第二个构造函数,在 x 方向上,fromXType、toXType 有三种类型:Animation.ABSOLUTE、
Animation.RELATIVE_TO_SELF、Animation.RELATIVE_TO_PARENT,分别代表绝对像素、相对于
自身平移、相对于父 View 平移。fromXValue、toXValue,当 type 为 Animation.ABSOLUTE 时,
这 个 两 个 值 为 具 体 的 像 素 值 , 当 type 为 Animation.RELATIVE_TO_SELF 或
Animation.RELATIVE_TO_PARENT,这个两个值为比例值,取值范围是[0f, 1.0f], y 方向上同
理。
具体的用法如下:
TranslateAnimation translateAnimation = new TranslateAnimation(Animation.RELATIVE_TO_SELF,
0f,
Animation.RELATIVE_TO_SELF, 0f, Animation.RELATIVE_TO_SELF, 0f,
Animation.RELATIVE_TO_SELF, -1.0f);
translateAnimation.setDuration(2000);
translateAnimation.setFillAfter(true);
view.startAnimation(translateAnimation);
此时 type 都是 Animation.RELATIVE_TO_SELF,toYValue 的值是-1.0f,即 100%,此时则 view
向 上 平 移 自 身 高 度 的 距 离 , 即 就 是 常 见 的 隐 藏 title 的 效 果 。 当 type 为
Animation.RELATIVE_TO_PARENT 时,则 view 向上平移父 view 高度距离。

1.2 缩放动画
缩放动画是通过 ScaleAnimation 类实现的,常用构造函数如下:
public ScaleAnimation(float fromX, float toX, float fromY, float toY,
int pivotXType, float pivotXValue, int pivotYType, float pivotYValue) {
}
x 方向上,参数 fromX、toX 分别代表 view 在水平方向缩放的起始比例和结束比例,都是大
于 等 于 0 的 浮 点 数 。 pivotXType 代 表 缩 放 类 型 , 有 三 种 Animation.ABSOLUTE, 、
Animation.RELATIVE_TO_SELF、Animation.RELATIVE_TO_PARENT,pivotXValue 代表缩放的中心
点,可以是具体的像素值,可以是比比例值,比例值范围是[0f, 1.0f],比例值是常用的,y
方向上同理。
具体用法如下:
ScaleAnimation scaleAnimation = new ScaleAnimation(1.0f, 2f, 1.0f, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setDuration(2000);
scaleAnimation.setFillAfter(true);
view.startAnimation(scaleAnimation);
实现了 view 相对于自身中心,在 x 方向拉伸为原来 2 倍,在 y 方向缩小为原来 0.5 倍。

1.3 旋转动画
旋转动画是通过 RotateAnimation 实现的,常用构造函数如下:
public RotateAnimation(float fromDegrees, float toDegrees, int pivotXType, float pivotXValue,
int pivotYType, float pivotYValue) {
}
参数 fromDegrees、toDegrees 代表旋转的开始角度和结束角度,pivotXValue、pivotYValue 代
表旋转的中心位置,可以是绝对的像素值,也可以是比例值,比例值范围是[0f, 1.0f],
pivotXType 、 pivotYType 代 表 旋 转 类 型 , 有 三 种 Animation.ABSOLUTE, 、
Animation.RELATIVE_TO_SELF、Animation.RELATIVE_TO_PARENT
具体用法如下:
RotateAnimation rotateAnimation = new RotateAnimation(0f, 360f, Animation.RELATIVE_TO_SELF,
0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setDuration(2000);
rotateAnimation.setFillAfter(true);
view.startAnimation(rotateAnimation);
实现了 view 相对自身中心,瞬时间旋转 360 度。

1.4 透明度动画
透明度动画通过 AlphaAnimation 类实现,构造函数如下:
public AlphaAnimation(float fromAlpha, float toAlpha) {
}
参数 fromAlpha、toAlpha 代表透明度的起始值和结束值,0f 代表完全透明,1.0f 则无透明度。
具体用法如下:
AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0);
alphaAnimation.setDuration(2000);
alphaAnimation.setFillAfter(true);
view.startAnimation(alphaAnimation);
实现了 view 从无透明度到完全透明的变化。
1.5 View 的组合动画
View 的组合动画通过 AnimationSet 类实现的,具体用法如下:
AnimationSet animationSet = new AnimationSet(true);
RotateAnimation rotateAnimation = new RotateAnimation(0f, 360f,
Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
AlphaAnimation alphaAnimation = new AlphaAnimation(1, 0);
animationSet.addAnimation(rotateAnimation);
animationSet.addAnimation(alphaAnimation);
animationSet.setFillAfter(true);
animationSet.setDuration(2000);
view.startAnimation(animationSet);
AnimationSet 的参数为 true 表示组合动画公用一个插值器,什么是插值器呢?就是动画速度
的变化规律,常用的插值器如下:
LinearInterpolator:匀速
AccelerateInterpolator:加速
AccelerateDecelerateInterpolator:先加速再减速
DecelerateInterpolator:减速
BounceInterpolator:阻尼下落,即反弹数次后停止
可通过如下方式使用
RotateAnimation rotateAnimation = new RotateAnimation(0f, 360f, Animation.RELATIVE_TO_SELF,
0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
rotateAnimation.setDuration(2000);
rotateAnimation.setFillAfter(true);
rotateAnimation.setInterpolator(new AccelerateInterpolator());
view.startAnimation(rotateAnimation);
最后,还可以通过 setRepeatCount()、setRepeatMode()来设置动画重复的次数、和重复模式,
重复模式包括 Animation.RESTART、Animation.REVERSE,即重新开始和逆序播放。
如果要监听动画的执行情况,则可以通过如下接口:
public static interface AnimationListener {
//开始
void onAnimationStart(Animation animation);
//结束
void onAnimationEnd(Animation animation);
//重复
void onAnimationRepeat(Animation animation);
}

2. 通过 xml 方式实现
xml 文件需要放到 res 目录下的 anim 文件夹。
2.1 平移动画
通过<translate >标签实现。
实现 View 向上平移自身高度距离,即 title 隐藏效果:
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:fillAfter="true"
android:fromXDelta="0%"
android:fromYDelta="0%"
android:toXDelta="0%"
android:toYDelta="-100%" />
实现 View 向上平移 50 像素
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:fillAfter="true"
android:fromXDelta="0"
android:fromYDelta="0"
android:toXDelta="0"
android:toYDelta="-50" />
2.2 缩放动画
通过<scale >标签实现。
实现 View 相对于自身中心,在 x 方向拉伸为原来 2 倍,在 y 方向缩小为原来 0.5 倍:
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:fromXScale="1.0"
android:fromYScale="1.0"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="2.0"
android:toYScale="0.5" />
2.3 旋转动画
通过<scale >标签实现。
实现 View 相对自身中心,瞬时间旋转 360 度,同时逆序重复两次:
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:repeatCount="2"
android:repeatMode="reverse"
android:toDegrees="360" />
2.4 透明度动画
通过<alpha>标签实现。
实现了 View 透明度从 1.0f 到 0f 的变化,同时是加速变化的:
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:fromAlpha="1.0"
android:interpolator="@android:anim/accelerate_interpolator"
android:toAlpha="0" />
2.5 View 的组合动画
通过<set>标签实现,但不能控制次序,只能同时发生,测试中发现,此时 repeatCount 属相
无效。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="5000"
android:fillAfter="true"
android:interpolator="@android:anim/linear_interpolator"
android:shareInterpolator="true">
<alpha
android:fromAlpha="1.0"
android:toAlpha="0" />
<rotate
android:fromDegrees="0"
android:pivotX="50%"
android:pivotY="50%"
android:toDegrees="360" />
<scale
android:fromXScale="1.0"
android:fromYScale="1.0"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="1.5"
android:toYScale="0.5" />
<translate
android:fromXDelta="0%"
android:fromYDelta="0%"
android:toXDelta="0%"
android:toYDelta="-100%" />
</set>
通过 xml 方式实现时,需要先通过 loadAnimation()加载 xml 文件,如下:
Animation animation = AnimationUtils.loadAnimation(context, R.anim.set_anim);
animation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
view.startAnimation(animation);
补间动画在 Android 最初的版本就有了,在功能和可扩展方面都有相当大的局限性,例如平
移效果只能改变 View 的显示效果而已,并不能改变 View 真正的位置,举个例子,如果将
一个有点击事件的 Button 从屏幕左上角移动到屏幕右上角,点击右上角按钮,发现并不能
响应点击事件,此时再点击屏幕左上角竟然有响应。还有补间动画只能作用于 View,如果
我们要对一个 View 的对象进行动画操作,那就无能为力了,正式因为种种功能上的缺陷,
Android 在 3.0 版本中引入了属性动画来进一步完善 Android 的动画机制。

二、属性 动画 (Property Animation )
有了属性动画,我们除了最基本的对 View 进行平移、缩放、旋转、透明度操作外,还可以
将动画作用于指定的对象上,例如将一个 Point 对象从(0, 0)位置移动到(100, 100)位置。但是
要注意, 属性动画在 只能在 Android3.0 即以上版本使用,如果要兼容 Android3.0
以下版本,可以考虑使用大神 JakeWharton 的动画库:http://nineoldandroids.com/,但是这
个库在 Android3.0 以下的属性动画其实还是传统的补间动画哦!
属性动画中核心的两个类就是 ValueAnimator 和 ObjectAnimator。
1. ValueAnimator
是用来计算动画对应属性初始值和结束值之间的过渡的,类似于一个数值发生器,例如我们
要实现数值 0 到数值 2 再到数值 0 在 2000 毫秒的过渡,可以这样做:
ValueAnimator animator = ValueAnimator.ofFloat(0f, 2f, 0f);
//设置监听器
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float curValue = (float) animation.getAnimatedValue();//当前值
float fraction = animation.getAnimatedFraction();//当前已过渡完成的比例
}
});
animator.setDuration(2000);//动画时长
animator.start();
ValueAnimator.ofFloat()是实现浮点数的平滑过渡,如果需要整数的平滑过渡则可以使用
ValueAnimator.ofInt() ,用法基本一致。除了这两个外还有 ValueAnimator.ofArgb() 、
ValueAnimator.ofObject(),其中 ValueAnimator.ofArgb()可以用来进行颜色值的过渡,
ValueAnimator.ofObject()可以用来实现对象的过渡效果,这是就需要我们自行定义扩展了。
ValueAnimator.ofFloat()是如何实现过渡效果的呢?其实就是通过一个 FloatEvaluator 来完成
的,不断的计算当前的值:
public class FloatEvaluator implements TypeEvaluator {
public Object evaluate(float fraction, Object startValue, Object endValue) {
float startFloat = ((Number) startValue).floatValue();
return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
}
}
如果我们要从点 Point(0, 0)过渡到点 Point(100, 100),同样也需要实现一个 TypeEvaluator 来
计算当前的过渡属性值:
public class PointEvaluator implements TypeEvaluator {
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
Point startPoint = (Point) startValue;
Point endPoint = (Point) endValue;
float x = startPoint.x + fraction * (endPoint.x - startPoint.x);
float y = startPoint.y + fraction * (endPoint.y - startPoint.y);
return new Point((int) x, (int) y);
}
}
很简单,fraction 代表已经过渡完成的比例,根据当前完成的比例、开始点和结束点计算出
当前点的值。有了 PointEvaluator 就可以实现我们自己的 Point 过渡效果了:
Point startPoint = new Point(0, 0);
Point endPoint = new Point(100, 100);
ValueAnimator animator = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Point currPoint = (Point) animation.getAnimatedValue();
}
});
这样就通过 TypeEvaluator 实现了一个我们自定义的估值器。
2. ValueAnimator
只是对值进行了一个平滑的动画过渡,ObjectAnimator 才是实现对任意对象的属性进行动画
操作的,同是 ObjectAnimator 是 ValueAnimator 的子类。先看一下如何通过 ObjectAnimator
实现传统补间动画的四种效果:
2.1 平移动画
要将一个 View 右移出屏幕,再移动回来,可以这样做:
float translationX = view.getTranslationX();
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "translationX", translationX, 600f,
translationX);
animator.setDuration(3000);
animator.start();
通过 ofFloat()方法我们创建了一个 ObjectAnimator 对象,ofFloat()方法的首个参数 view 就是
要进行平移操作的对象,因为我们要对 view 进行平移操作,所以第二个参数传入
translationX,代表 view 的平移属性,之后的参数是一个是可变长度的,个数根据你的需求
控制。所以核心的参数就是第二个,根据这个属性类型来区分对 View 进行何种动画操作。
2.2 缩放动画
同样的道理,实现 View 的缩放效果可以这样做:
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "scaleX", 1f, 2f, 1f);
animator.setDuration(5000);
animator.start();
我们将 ofFloat()方法第二个参数换成了 scaleX,表示在 x 方向对 view 进行缩放操作,这样我
们就实现了 view 拉伸两倍再还原的效果。
2.3 旋转动画
例如,要将一个 View 旋转 360 度可以这样做,只要将 ofFloat()第二个参数写成 rotation,起
始、结束角度分别为 0 和 360:
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "rotation", 0f, 360f);
animator.setDuration(3000);
animator.start();
2.4 透明度动画
只要将 ofFloat()第二个参数写成 alpha,则实现了 View 透明度从 1 到 0 在到 0 的变化:
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f, 1f);
animator.setDuration(5000);
animator.start();
2.5 颜色动画
使用属性动画改变一个 View 的背景颜色也是可以的,如下代码可以实现 View 背景色从蓝
到红的变化:
ObjectAnimator animator = ObjectAnimator.ofFloat(view, "backgroundColor", Color.BLUE,
Color.RED);
animator.setEvaluator(new ArgbEvaluator());animator.setDuration(5000);
animator.start();
2.6 组合动画
和补间动画类似,属性动画同样可以将单个动画进行组合,而且功能更强大,需要通过
AnimatorSet 类来实现,通过调用其 play()方法得到一个 AnimatorSet.Builder 对象,Builder 对
象有以下四个方法:
(1)after(Animator anim) 将现有动画插入到传入的动画之后执行;
(2)after(long delay) 将现有动画延迟指定毫秒后执行;
(3)before(Animator anim) 将现有动画插入到传入的动画之前执行;
(4)with(Animator anim) 将现有动画和传入的动画同时执行 。
我们要实现一个 View 从屏幕右侧移入屏幕,然后旋转 360 度同时有透明度变化,最后在水
平方向拉伸两倍后还原的效果可以这样么做:
AnimatorSet animatorSet = new AnimatorSet();
ObjectAnimator alpha = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f, 1f);
ObjectAnimator rotation = ObjectAnimator.ofFloat(view, "rotation", 0f, 360f);
ObjectAnimator translation = ObjectAnimator.ofFloat(view, "translationX", 600f, 0f);
ObjectAnimator scale = ObjectAnimator.ofFloat(view, "scaleX", 1f, 2f, 1f);
animatorSet.play(alpha).with(rotation).after(translation).before(scale);
animatorSet.setDuration(5000);
animatorSet.start();
当然还可以 setRepeatCount()、setRepeatMode()设置动画的重复次数以及重复模式,重复模
式有 ValueAnimator.RESTART、ValueAnimator.REVERSE 两种。
3. 除了通过代码来编写属性动画外,还可以使用 xml 的方式,xml 文件需要放到 res 目录下
的 的 animator 文件夹。
可用的标签有以下三种:
• <animator> 代表 ValueAnimator
• <objectAnimator> 代表 ObjectAnimator
• <set> 代表 AnimatorSet
好了,看几个例子:
要实现 0 到 50 平滑过渡的效果,可以这么做:
• <?xml version="1.0" encoding="utf-8"?>
• <animator xmlns:android="http://schemas.android.com/apk/res/android"
• android:duration="2000"
• android:valueFrom="0"
• android:valueTo="50"
android:valueType="floatType" />
要将一个 View 旋转 360 度,可以这么做:
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="360"
android:valueType="floatType" />
要将一个 View 透明度从 1 变为 0,可以这样编写:
<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:propertyName="alpha"
android:valueFrom="1"
android:valueTo="0"
android:valueType="floatType" />
平移和缩放动画都是类似的。再看一下<set>标签的用法:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="sequentially">
<objectAnimator
android:duration="1500"
android:propertyName="translationX"
android:valueFrom="-500"
android:valueTo="0"
android:valueType="floatType" />
<set android:ordering="together">
<objectAnimator
android:duration="2000"
android:propertyName="rotation"
android:valueFrom="0"
android:valueTo="360"
android:valueType="floatType" />
<set android:ordering="sequentially">
<objectAnimator
android:duration="1000"
android:propertyName="alpha"
android:valueFrom="1"
android:valueTo="0"
android:valueType="floatType" />
<objectAnimator
android:duration="1000"
android:propertyName="alpha"
android:valueFrom="0"
android:valueTo="1"
android:valueType="floatType" />
</set>
</set>
<set android:ordering="together">
<objectAnimator
android:duration="1500"
android:propertyName="scaleX"
android:valueFrom="1"
android:valueTo="2"
android:valueType="floatType" />
<objectAnimator
android:duration="1500"
android:propertyName="scaleX"
android:valueFrom="2"
android:valueTo="1"
android:valueType="floatType" />
</set>
</set>
我们实现了 View 先平移,然后同时进行旋转和透明度变化,最后进行缩放的动画效果。其
中 ordering 属相我们使用了 sequentially、together 两种,分别代表顺序播放和同时播放。还
有以下两个我们没用到的属性:startOffset:表示动画的延时启动时间,以及 repeatCount、
repeatMode。
使用 xml 动画文件也是非常简单的:
Animator animator = AnimatorInflater.loadAnimator(context, R.animator.anim_file);
animator.setTarget(view);
animator.start();
4. Animator 类当中提供了一个 addListener()方法,可以用来监听动画的执行情况,无论
ObjectAnimator、ValueAnimator 还是 AnimatorSet 都是 Animator 的子类,所以它们都可以使
用 addListener():
anim.addListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) {
}
@Override
public void onAnimationEnd(Animator animation) {
}
@Override
public void onAnimationCancel(Animator animation) {
}
@Override
public void onAnimationRepeat(Animator animation) {
}
});
如果想监听其中的某些事件则可以通过 AnimatorListenerAdapter 来实现:
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
super.onAnimationStart(animation);
}
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
}
});
这样我们只监听了动画的开始和结束事件。
5. 属性动画的插值器是兼容补间动画的插值器的,所以补间动画中的插值器完全可以在属
性动画中使用。另外属性动画提供了一个 TimeInterpolator 接口,它的作用是根据时间流逝
的百分比计算出当前属性值改变的百分比,通过这个接口我们来自定义属性动画插值器:
public interface TimeInterpolator {
/**
* Maps a value representing the elapsed fraction of an animation to a value that represents
* the interpolated fraction. This interpolated value is then multiplied by the change in
* value of an animation to derive the animated value at the current elapsed animation
time.
*
* @param input A value between 0 and 1.0 indicating our current point
* in the animation where 0 represents the start and 1.0 represents
* the end
* @return The interpolation value. This value can be more than 1.0 for
* interpolators which overshoot their targets, or less than 0 for
* interpolators that undershoot their targets.
*/
float getInterpolation(float input);
}
接口中只有一个 getInterpolation()方法,其中 input 参数会根据动画设置的时长在 0 到 1 之
间匀速增长的变化。如果要自定义插值器可以这样写:
public class MyInterpolator implements TimeInterpolator {
@Override
public float getInterpolation(float input) {
float result = 0;
//todo
return result;
}
}
考验数学功底的时候来了。。。。具体的实现细节可参考系统插值器。有一点需要注意,我们
计算出来的 result 的值必须在 0 到 1 之间。
6. 回顾一下,我们在 java 代码中可以通过 ObjectAnimator.ofFloat()或 ObjectAnimator.ofInt()
来实现属性动画其中第二个参数可以是 alpha、rotation、scaleX、translateX 等等。为什么第
二个参数可以是这些呢?这是因为 ObjectAnimator 内部的工作机制并不是对传入的属性名
进行操作的,而是根据属性名在当前子 View 类以及父类中去找对应的 get 和 set 方法,然
后通过方法不断地对值进行改变,从而实现动画效果的,例如我们可以在 View 类中找到了
参数 rotation 对应的 get 和 set 方法:
public float getRotation() {
return mRenderNode.getRotation();
}
public void setRotation(float rotation) {
if (rotation != getRotation()) {
// Double-invalidation is necessary to capture view's old and new areas
invalidateViewProperty(true, false);
mRenderNode.setRotation(rotation);
invalidateViewProperty(false, true);
invalidateParentIfNeededAndWasQuickRejected();
notifySubtreeAccessibilityStateChangedIfNeeded();
}
}
既然如此,除了系统提供的属性动画外,如果要给一个自定义 Button 添加一个 widths 属相
动画,实现其宽度的变化,如果使用 translateX 属性会导致 Button 内容的拉伸,这并不是我
们愿意看到的,所以我们自定义的 widths 属相动画并没有这种问题。首先看我们自定义的
Button 类:
public class MyButton extends Button{
public MyButton(Context context) {
super(context);
}
public MyButton(Context context, AttributeSet attrs) {
super(context, attrs);
}
public int getWidths(){
return getLayoutParams().width;
}
public void setWidths(int width){
getLayoutParams().width = width;
requestLayout();
}
}
因为我们规定属性名为 widths,所以我们提供了 getWidths()、setWidths()两个方法,当然这
两个方法也是必须的。接下来还需要编写一个 TypeEvaluator 类来告诉系统宽度如何过渡:
public class WidthsEvaluator implements TypeEvaluator {
@Override
public Object evaluate(float fraction, Object startValue, Object endValue) {
int startWidth = (int) startValue;
int endWidth = (int) endValue;
return (int)(startWidth + fraction * (endWidth - startWidth));
}
有了 WidthsEvaluator 类,我们需要的东西也就够了,看下布局文件、以及使用方法:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.example.othershe.mybutton.MyButton
android:id="@+id/my_btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="哎呦,不错哦!" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="start"
android:text="开始" />
</RelativeLayout>
public class MainActivity extends AppCompatActivity {
private MyButton button;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button = (MyButton) findViewById(R.id.my_btn);
}
public void start(View view) {
int width = button.getWidth();
ObjectAnimator animator = ObjectAnimator.ofObject(button, "widths", new
WidthsEvaluator(), width, 600);
animator.setDuration(3000);
animator.start();
}
}
通过 ObjectAnimator.ofObject()来调用的,很简单。
7. 通过 java 代码实现属性动画除了通过 ObjectAnimator 类,还有另外一种方式,就是使用
ViewPropertyAnimator 类。例如我们要实现一个球形 View 自由落体的效果,可以这样写:
view.animate().x(0).y(500)
.setDuration(5000)
.setInterpolator(new BounceInterpolator());
通过 view.animate()方法得到一个 ViewPropertyAnimator 对象,之后的操作都是基于该对象
的方法,而且是链式调用的,同时在链尾系统会默认的添加 start()方法,所以动画会自动执
行。仅仅是写法的不同,根据喜好选择吧,其它的方法有兴趣的话可以自行测试

三、 帧动画 (Drawable Animation )
帧动画是顺序的播放一系列图片,从而产生动画的效果,其实也就是图片的切换。但是如果
图片过多、过大的话是很容易产生 OOM 的,所以使用时需要注意。
首先在 res 目录下的 drawable 文件夹编写一个 xml 文件:
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="true">//
<item android:drawable="@mipmap/icon1" android:duration="300"/>
<item android:drawable="@mipmap/icon2" android:duration="300"/>
<item android:drawable="@mipmap/icon3" android:duration="300"/>
<item android:drawable="@mipmap/icon4" android:duration="300"/>
<item android:drawable="@mipmap/icon5" android:duration="300"/>
<item android:drawable="@mipmap/icon6" android:duration="300"/>
<item android:drawable="@mipmap/icon7" android:duration="300"/>
<item android:drawable="@mipmap/icon8" android:duration="300"/>
<item android:drawable="@mipmap/icon9" android:duration="300"/>
</animation-list>
oneshot 属性表示是否循环播放,值为 true 则只播放一次。
通如下方法调用,其中 view 是一个 ImageView 对象:
view.setImageResource(R.drawable.icons);
AnimationDrawable animationDrawable = (AnimationDrawable) view.getDrawable();
animationDrawable.start();
如果要停止播放可通过如下方法:
AnimationDrawable animationDrawable = (AnimationDrawable) view.getDrawable();
animationDrawable.stop();
到这里 Android 动画相关的内容就结束了,足以应对开发中的使用场景了。

posted @ 2017-03-09 19:37  韩同学  阅读(119)  评论(0)    收藏  举报