Android 3.0之前已有View动画框架Animation(详见:Android之视图动画Animation),但存在一些局限性,当某个元素发生视图动画后,其响应事件位置还在动画前的地方。于是3.0之后,Google提出了属性动画。
Animation的优点
1. 版本兼容
不得不说,相对于 Animation,Animator 的版本兼容性还是太差,直到 Android3.0才开始出现的 Animator, 是无法满足目前开发环境2.x 的兼容支持的,而且在 android 官方的 support 包中也没有对于低版本的 Animator 进行支持,所以单从版本兼容来看, Animator 还是不够的,不过这是系统历史原因,我们只能接受.
2.实现效率
同样的,这也是 Animator 的一个缺点,由于 Animator 是直接通过设置对象的 setter,getter 方法,来起到动画显示效果的,所以为了满足对任意对象调用正确方法,Animator 使用了 Java 反射机制, 而 Animation 则是直接通过代码对矩阵进行处理,所以就效率这一方面而言, Animator比不上 Animation
Animator的实现原理
Animator 动画的实现机制说起来其实更加简单一点,因为他其实只是计算动画开启之后,结束之前,到某个时间点得时候,某个属性应该有的值,然后通过回调接口去设置具体值,其实 Animator 内部并没有针对某个 view 进行刷新,来实现动画的行为,动画的实现是在设置具体值的时候,方法内部自行调取的类似 invalidate 之类的方法实现的.也就是说,使用 Animator ,内部的属性发生了变化.
Animator的优点
1. 适用性
在上一个分析中,我们看到了由于 Animator 使用了反射机制导致其效率偏低,但是这也带来了他适用的对象范围的增加, Animation 仅对 View 这一种对象有用,但是 Animator 可以设置任意对象的属性,使其在某段时间内进行变化
2. 使用效果
相信大家平时使用 Animation 的时候,都有发现当正在进行平移移动,或者动画结束后,但位置发生改变的时候,你点击之前的位置,点击效果仍然存在,这就是因为 View 在内部的坐标位置其实没有发生改变,而如果使用 Animator 进行位移变换,那么你的点击位置就会随着动画效果发生相应改变,所以即使你正处在动画过程中,你也可以去点击按钮得到你想要的效果.
-----------------------------------------------
补间动画
- 视图动画,也叫Tween(补间)动画可以在一个视图容器内执行一系列简单变换(位置、大小、旋转、透明度)。譬如,如果你有一个TextView对象,您可以移动、旋转、缩放、透明度设置其文本,当然,如果它有一个背景图像,背景图像会随着文本变化。
- 补间动画通过XML或Android代码定义,建议使用XML文件定义,因为它更具可读性、可重用性。
如下是视图动画相关的类继承关系:
AlphaAnimation <alpha> 放置在res/anim/目录下 渐变透明度动画
RotateAnimation <rotate> 放置在res/anim/目录下 画面转移旋转动果
ScaleAnimation <scale> 放置在res/anim/目录下 渐变尺寸伸缩动画
TranslateAnimation <translate> 放置在res/anim/目录下 画面转换位置移动动画效果
AnimationSet <set> 放置在res/anim/目录下 一个持有其它动画元素alpha、scale、translate、rotate或者其它set元素的容器
Animation属性详解
android:detachWallpaper setDetachWallpaper(boolean) 是否在壁纸上运行
android:duration setDuration(long) 动画持续时间,毫秒为单位
android:fillAfter setFillAfter(boolean) 控件动画结束时是否保持动画最后的状态
android:fillBefore setFillBefore(boolean) 控件动画结束时是否还原到开始动画前的状态
android:fillEnabled setFillEnabled(boolean) 与android:fillBefore效果相同
android:interpolator setInterpolator(Interpolator) 设定插值器(指定的动画效果,譬如回弹等)
android:repeatCount setRepeatCount(int) 重复次数
android:repeatMode setRepeatMode(int) 重复类型有两个值,reverse表示倒序回放,restart表示从头播放
android:startOffset setStartOffset(long) 调用start函数之后等待开始运行的时间,单位为毫秒
android:zAdjustment setZAdjustment(int) 表示被设置动画的内容运行时在Z轴上的位置(top/bottom/normal),默认为normal
LinearLayout layout = (LinearLayout) findViewById(R.id.test_layout );
ScaleAnimation scaleAnimation = new ScaleAnimation(0,1,0,1);
scaleAnimation.setDuration(2000);
LayoutAnimationController layoutAnimationController = new LayoutAnimationController(scaleAnimation,0.5f);
layoutAnimationController.setOrder(LayoutAnimationController.ORDER_NORMAL);
layout .setLayoutAnimation(layoutAnimationController);
AnimationSet详解
AnimationSet继承自Animation,是上面四种的组合容器管理类,没有自己特有的属性,他的属性继承自Animation,所以特别注意,当我们对set标签使用Animation的属性时会对该标签下的所有子控件都产生影响。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@[package:]anim/interpolator_resource"
android:shareInterpolator=["true" | "false"] >
<alpha
android:fromAlpha="float"
android:toAlpha="float" />
<scale
android:fromXScale="float"
android:toXScale="float"
android:fromYScale="float"
android:toYScale="float"
android:pivotX="float"
android:pivotY="float" />
<translate
android:fromXDelta="float"
android:toXDelta="float"
android:fromYDelta="float"
android:toYDelta="float" />
<rotate
android:fromDegrees="float"
android:toDegrees="float"
android:pivotX="float"
android:pivotY="float" />
<set>
...
</set>
</set>
至于补间动画的使用,Animation还有如下一些比较实用的方法介绍逐帧动画
属性动画
ObjectAnimator
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageView, "translationX", 300);
objectAnimator1.setInterpolator(new AccelerateInterpolator());
objectAnimator1.setDuration(2000);
objectAnimator.setRepeatCount(ValueAnimator.INFINITE);//Animation.INFINITE 表示重复多次
objectAnimator.setRepeatMode(ValueAnimator.RESTART);//RESTART表示从头开始,REVERSE表示从末尾倒播
objectAnimator1.start();
Animation 使用setFillAfter(true)让动画停留在原处
动画属性值
平移:
translationX和translationY:增量控制view从它布局容器左上角坐标偏移
ObjectAnimator.ofFloat(imageView, "translationX", 300f);
rotation 控制view旋转:
rotation、rotationX、rotationY:控制view绕支点进行旋转
ObjectAnimator.ofFloat(imageView, "rotation", 360);
// 翻转
ObjectAnimator rotateX = ObjectAnimator.ofFloat(mTvText, "rotationX", 0, 360);
rotateX.setDuration(2000);
rotateX.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
// 属性动画执行时,会回调这个监听器
// 如果你的属性没有触发重绘,那你可以在这里加上invalidate()或postInvalidate()
Log.d(TAG, "onAnimationUpdate: value=" + animation.getAnimatedValue()
+ "fraction=" + animation.getAnimatedFraction());
}
});
scaleX、scaleY:控制view进行缩放:
scaleX、scaleY:控制view绕支点进行缩放
ObjectAnimator.ofFloat(imageView, "scaleX", 1f, 0.3f,1f);
alpha:控制view透明度:
alpha:控制view透明度,默认是1(不透明),0完全透明(不可见)
ObjectAnimator.ofFloat(imageView, "alpha", 1f, 0.3f);
可变数组参数
可以有一个到N个,如果是一个值的话默认这个值是动画过渡值的结束值。如果有N个值,动画就在这N个值之间过渡。
动画监听:
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageView, "alpha", 0.5f, 1f);
objectAnimator1.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) {
}
});
Android提供了AnimatorListenerAdapter:
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageView, "alpha", 0.5f, 1f);
objectAnimator1.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
}
});
XML中使用 ObjectAnimator
放置在res/animator/目录下
<objectAnimator>属性解释:
XML属性动画使用方法:
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
R.animtor.property_animator);
set.setTarget(myObject);
set.start();
ValueAnimator
ValueAnimator 本身不提供任何动画效果,像个数值 发生器,用来产生具有一点规律数字。
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 500);
valueAnimator.setTarget(mTvText);
valueAnimator.setDuration(2000);
/**
* valueAnimator 必须使用updateListener进行接收数据
* ValueAnimator不跟属性进行绑定
*/
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
// 在数值变化监听器中实现动画变换
mTvText.setTranslationX((Float) animation.getAnimatedValue());
}
});
valueAnimator.start();
PropertyValuesHolder 针对同一个对象多个属性,同时作用多种动画
PropertyValuesHolder propertyValuesHolder1 = PropertyValuesHolder.ofFloat("translationX", 300f);
PropertyValuesHolder propertyValuesHolder2 = PropertyValuesHolder.ofFloat("alpha", 1f, 0.5f);
PropertyValuesHolder propertyValuesHolder3 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f);
PropertyValuesHolder propertyValuesHolder4 = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f);
ObjectAnimator.ofPropertyValuesHolder(imageView, propertyValuesHolder1, propertyValuesHolder2, propertyValuesHolder3, propertyValuesHolder4)
.setDuration(5000).start();
AnimatorSet
与PropertyValuesHolder类似,但AnimatorSet多了playTogether(同时执行)、playSequentially(顺序执行)、play(objectAnimator1).with(objectAnimator2)、before、after这些方法协同工作。
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageView, "alpha", 1f, 0.5f);
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(imageView, "translationY", 300);
ObjectAnimator objectAnimator3 = ObjectAnimator.ofFloat(imageView, "scaleX", 1f, 0, 1f);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.setDuration(5000);
animatorSet.playTogether(objectAnimator1, objectAnimator2,objectAnimator3);
animatorSet.start();
AnimatorSet set = new AnimatorSet(); // 下面代码产生的规则并不能确定anim2与anim3的先后关系
// 下面代码产生的规则可间接确定anim2与anim3的先后关系
set.play(anim1).before(anim2).before(anim3);
// 下面代码产生的规则可完全确定anim1、anim2、anim3之间的先后关系
set.play(anim1).before(anim2).after(anim3);
set.play(anim1).before(anim2);
set.play(anim2).before(anim3);
xml使用属性动画
- res下建立animator文件夹,然后建立res/animator/main_animator.xml
- set标签,有一个orderring属性设置为together,还有另一个值:sequentially(表示一个接一个执行)。
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="2000"
android:valueType="floatType">
<objectAnimator
android:duration="1000"
android:propertyName="scaleX"
android:valueFrom="1"
android:valueTo="0.5" />
<objectAnimator
android:duration="1000"
android:propertyName="scaleY"
android:valueFrom="1"
android:valueTo="0.5" />
</set>
<!-- 代码中调用
Animator animator = AnimatorInflater.loadAnimator(getApplicationContext(), R.animator.set_animator);
animator.setTarget(imageView);
animator.start();
-->
View的animate方法
Android 3.0后,谷歌给View增加animate方法直接驱动属性动画。
imageView.animate()
.alpha(0.5f)
.y(300)
.setDuration(2000)
//api min is 16
.withStartAction(new Runnable() {
@Override
public void run() {
}
})
//api min is 16
.withEndAction(new Runnable() {
@Override
public void run() {
}
})
.start();