吐血总结【Android动画学习-你必须要知道的动画知识点】
Animations
动画系统:Developer-Animation
Android框架提供了两个动画系统:属性动画和视图动画。两个动画系统都是可行的选择,但是总的来说,属性动画系统是首选的方法,因为它更灵活,提供了更多的特性。
android3.0之后 动画分类如图: image.png
接下来我们具体讲解这三种动画:
一、视图动画:【ViewAnimation】
1. 帧动画(FrameAnimation):它允许您加载可绘制的资源,并将它们显示为一个接一个的帧。一帧一帧的动画,加载一系列Drawable资源来创建动画,这种传统动画某种程度上就是创建不同图片序列,顺序播放,就像电影胶片、幻灯片一样。(这种确实很简单,直接使用UI切好的图就行,但是图片过多,也十分容易内存溢出oom,所以一般不建议使用)
2. 补间动画(TweenAnimation) :AlphaAnimation(xml中alpha标签), RotateAnimation(xml中rotate标签), ScaleAnimation(xml中scale标签), TranslateAnimation(xml中translate标签),分别对应透明度、旋转、缩放、位移四种变化。
使用方式一:xml定制动画(文件处于res/anim/地址下)
-
alpha xml 淡入效果
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0"
android:duration="500" />
</set>
<!--
fromAlpha:开始时透明度
toAlpha: 结束时透明度
duration:动画持续时间 -->
-
rotate.xml 旋转效果:
<set xmlns:android="http://schemas.android.com/apk/res/android">
<rotate
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:fromDegrees="300"
android:toDegrees="-360"
android:pivotX="10%"
android:pivotY="100%"
android:duration="10000" />
</set>
<!--
fromDegrees 动画开始时的角度
toDegrees 动画结束时物件的旋转角度,正代表顺时针
pivotX 属性为动画相对于物件的X坐标的开始位置
----旋转中心的x坐标,浮点数或是百分比。浮点数表示相对于Object的左边缘,如5; 百分比表示相对于Object的左边缘,如5%; 另一种百分比表示相对于父容器的左边缘,如5%p; 一般设置为50%表示在Object中心
pivotY 属性为动画相对于物件的Y坐标的开始位置
--- 旋转中心的Y坐标,浮点数或是百分比。浮点数表示相对于Object的上边缘,如5; 百分比表示相对于Object的上边缘,如5%; 另一种百分比表示相对于父容器的上边缘,如5%p; 一般设置为50%表示在Object中心
duration 持续时间,表示从android:fromDegrees转动到android:toDegrees所花费的时间,单位为毫秒。1000ms=1s 可以用来计算速度。
interpolator表示变化率,但不是运行速度。一个插补属性,可以将动画效果设置为加速,减速,匀速,反复,反弹等。默认为开始和结束慢中间快.
其他:
android:repeatCount 重复的次数,默认为0,必须是int,可以为-1表示不停止
android:repeatMode 重复的模式,默认为restart,即重头开始重新运行,可以为reverse即从结束开始向前重新运行。在android:repeatCount大于0或为infinite时生效
android:detachWallpaper 表示是否在壁纸上运行
android:startOffset 在调用start函数之后等待开始运行的时间,单位为毫秒,若为10,表示10ms后开始运行
android:zAdjustment 表示被animated的内容在运行时在z轴上的位置,默认为normal。
normal保持内容当前的z轴顺序
top运行时在最顶层显示
bottom运行时在最底层显示
-->
-
scale.xml 缩放效果:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<scale
android:interpolator= "@android:anim/decelerate_interpolator"
android:fromXScale="0.0"
android:toXScale="1.5"
android:fromYScale="0.0"
android:toYScale="1.5"
android:pivotX="50%"
android:pivotY="50%"
android:startOffset="0"
android:duration="10000"
android:repeatCount="1"
android:repeatMode="reverse" />
</set>
<!--
fromXDelta,fromYDelta 起始时X,Y座标,屏幕右下角的座标是X:320,Y:480
toXDelta, toYDelta 动画结束时X,Y的座标 --> <!--
interpolator 指定动画插入器
常见的有加速减速插入器 accelerate_decelerate_interpolator
加速插入器 accelerate_interpolator,
减速插入器 decelerate_interpolator。
fromXScale,fromYScale, 动画开始前X,Y的缩放,0.0为不显示, 1.0为正常大小
toXScale,toYScale, 动画最终缩放的倍数, 1.0为正常大小,大于1.0放大
pivotX, pivotY 动画起始位置,相对于屏幕的百分比,两个都为50%表示动画从屏幕中间开始
startOffset, 动画多次执行的间隔时间,如果只执行一次,执行前会暂停这段时间,
单位毫秒 duration,一次动画效果消耗的时间,单位毫秒,
值越小动画速度越快 repeatCount,动画重复的计数,动画将会执行该值+1次
repeatMode,动画重复的模式,reverse为反向,当第偶次执行时,动画方向会相反。
restart为重新执行,方向不变 -->
-
translate.xml 移动效果:
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:fromXDelta="320"
android:toXDelta="0"
android:fromYDelta="480"
android:toYDelta="0"
android:duration="10000" />
</set>
<!--
fromXDelta,fromYDelta 起始时X,Y座标,屏幕右下角的座标是X:320,Y:480
toXDelta, toYDelta 动画结束时X,Y的座标 -->
加载xml动画:
//xml动画文件
ImageView imageBg = (ImageView) content.findViewById(R.id.imageView);
Animation animation = AnimationUtils.loadAnimation(context, R.anim.splash_scale);
animation.setInterpolator(new LinearInterpolator());
imageBg.startAnimation(animation);
使用方式二、java代码方式实现定制并加载动画
xml里有的动画属性都可以通过java代码创建。根据需要定制自己的动画
//平移动画 四个参数fromX,toX,fromY,toY。而这个X,Y都是相对于当前这个控件的位置来说的。
//就是从当前控件的(X+fromX,Y+fromY)移动到(X+toX,Y+toY),
//(其中这个X和Y是最刚开始这个控件的X和Y坐标。就是动画都还没开始的时候的坐标。)
ImageView imageBg = (ImageView) content.findViewById(R.id.imageView);
TranslateAnimation anim = new TranslateAnimation(0,100,0,100);
anim.setDuration(5000);
anim.setInterpolator(new LinearInterpolator());
anim.setFillAfter(true);
imageBg .startAnimation(anim);
AnimationListener和AnimationSet
通过AnimationListener可以监听Animation的运行过程,有三个方法分别是Animation开始的时候调用,完成的时候调用,重复的时候调用。
AnimationSet,动画集合。 我们最常用的是调用其 addAnimation 将一个个不一样的动画组织到一起来,然后调用view 的 startAnimation 方法触发这些动画执行。
AnimationSet as=new AnimationSet(true);
RotateAnimation al=new RotateAnimation(0,-720,Animation.RELATIVE_TO_PARENT,0.5f,Animation.RELATIVE_TO_PARENT,0.5f);
al.setDuration(3000);
al.setAnimationListener(new AnimationListener(){
public void onAnimationStart(Animation animation) {
// TODO Auto-generated method stub
}
public void onAnimationEnd(Animation animation) {
// TODO Auto-generated method stub
}
public void onAnimationRepeat(Animation animation) {
// TODO Auto-generated method stub
}
});
as.addAnimation(al);
iv.startAnimation(as);
setAnimation和startAnimation区别
setAnimation是告诉该控件我待会要执行什么动画,而要执行的的动画,是需要手动添加的。并且需要父view在动画快要开启的时候,调用invalidate。需要一定的条件限制。
而startAnimation告诉该控件,我要立马执行该动画,该动画就是已经设置好的动画。调用它时就会立即开始动画。
属性动画 【PropertyAnimation】
对比
ViewAnimation本身是通过改变View的绘制方式来实现动画的,View对象本身的属性值并没有改变,对象仍然停留在原始位置.
Property Animation系统可以通过修改 View 对象实际的属性值(属性会有相应的 getter、setter )来实现屏幕上的动画效果。此外,当属性值发生变化时,Views 也会自动调用 invalidate() 方法来刷新屏幕。
View Animation相当简单,不过只能支持简单的缩放、平移、旋转、透明度基本的动画和帧动画,且有一定的局限性。比如:
- 你希望View有一个颜色的切换动画;
- 你希望可以使用3D旋转动画;
- 你希望当动画停止时,View的位置就是当前的位置;
- 修改组件的背景颜色
这些View Animation都无法做到。
这也就是Property Animation产生的原因。
PropertyAnimation就是通过动画的方式改变对象的属性。
接下来我们详细讲解PropertyAnimation。
1.PropertyAnimation-沿一定时间顺序,通过改变View的属性,从而得到动画效果。使得“眼见为实”,动画之后,Object对象的属性值被实实在在的改变了。Property animation能够通过改变View对象的实际属性来实现View动画,任何时候View属性的改变,View能自动调用invalidate()来实时刷新。
2.总的来说,属性动画就是,动画的执行类
来设置动画操作的对象的属性
(持续时间,开始和结束的属性值,时间差值等),然后系统会根据设置的参数
动态的变化对象的属性。
- 动画的执行类:
- ObjectAnimator
- ValueAnimator
- 对象的属性:
- Duration:动画的持续时间,默认300ms
- Time Interpolation : 时间插值【LinearInterpolator、AccelerateInterpolator、DecelerateInterpolator等】
- Repeat count and behavior:重复次数、以及重复模式;可以定义重复多少次;重复时从头开始,还是反向。
- Animator sets : 动画集合,你可以定义一组动画,一起执行或者顺序执行。
- 其他重要的类:
- AnimatorInflater 用户加载属性动画的xml文件
- TypeEvaluator 类型估值,主要用于设置动画操作属性的值。
- TimeInterpolator 时间插值
- AnimatorSet 用于控制一组动画的执行:线性,一起,每个动画的先后执行等。
- PropertyValuesHolder 针对同一个对象多个属性,同时作用多种动画
接下来讲解属性动画在实践中的使用:
【关于Interpolator、TypeEvaluator】
参看这篇文章:Android动画之Interpolator插补器和TypeEvaluator估值器
【关于Animator监听器 】
Property Animation提供了Animator.AnimatorListener和Animator.AnimatorUpdateListener两个监听器用于动画在播放过程中的重要动画事件。下面是两个监听器接口和方法的一些介绍和说明:
- Animator.AnimatorListener:
onAnimationStart() —— 动画开始时调用;
onAnimationEnd() —— 动画结束时调用;
onAnimationRepeat() —— 动画循环播放时调用;
onAnimationCancel() —— 动画被取消时调用。不管终止的方式如何,被取消的动画仍然会调onAnimationEnd();- 此监听器还有一个子类AnimatorListenerAdapter,两者的区别是AnimatorListener的方法需要全部实现,而AnimatorListenerAdapter可以选择我们所需要的方法实现,比如通常情况我们只关心onAnimationEnd。
animator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
super.onAnimationEnd(animation);
}
});
animator.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) {
}
});
- Animator.AnimatorUpdateListener(通常和ValueAnimator搭配使用):
onAnimationUpdate() —— 动画每播放一帧时调用。
在动画过程中,可侦听此事件来获取并使用 ValueAnimator 计算出来的属性值;
利用传入事件的 ValueAnimator 对象,调用其 getAnimatedValue() 方法即可获取当前的属性值。如果使用ValueAnimator来实现动画的话 ,则必需实现此侦听器。
【关于AnimatorInflater】
上面讲到ViewAnimation有许多xml加载,当然PropertyAnimation也可以对应xml加载,位置为res/animator/
animator.xml
<?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="0.1"
android:valueTo="1.0"
android:valueType="floatType" />
调用就用到了AnimatorInflater类了
Animator animator = AnimatorInflater.loadAnimator(getApplicationContext(), R.animator.animator);
animator.setTarget(imageView);
animator.start();
组合动画也可以xml加载
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:ordering="together">
orderring属性设置为together,还有另一个值:sequentially(表示一个接一个执行)。
<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>
【关于动画属性值】
在 Android 3.0 中给 View 增加了一些新的属性以及相应的 getter、setter 方法。Property Animation系统可以通过修改 View 对象实际的属性值来实现屏幕上的动画效果。此外,当属性值发生变化时,Views 也会自动调用 invalidate() 方法来刷新屏幕。 View 类中新增的便于实现 property 动画的属性包括:
- translationX和translationY:增量控制view的坐标偏移
- rotation、rotationX 和 rotationY:这三个属性控制着 2D 旋转角度(rotation属性)和围绕某枢轴点的 3D 旋转角度;
- scaleX、scaleY:控制view绕支点进行2D缩放
- x 和 y:这是指 View 在容器内的最终位置,等于 View 左上角相对于容器的坐标加上 translationX 和 translationY 后的值;
- alpha:表示 View 的 alpha 透明度。缺省值为 1 (不透明),为 0 则表示完全透明(看不见);
上述我们提到的属性也就是接下来ObjectAnimator使用中的第二个参数,操作对象的属性值。
当然我们也可以自定义view的动画属性,但必须带有一个 setter 方法(以骆驼拼写法命名),格式类似 set<propertyName>()。 因为 ObjectAnimator 会在动画期间自动更新属性值,它必须能够用此 setter 方法访问到该属性。getter不是必须,而什么时候必须需要getter方法呢?如果在调用 ObjectAnimator 的某个工厂方法时,我们只为 values... 参数指定了一个值,那此值将被认定为动画属性的结束值。 这样的话,动画显示的属性必须带有一个 getter 方法,用于获取动画的起始值。 此 getter 方法必须以get<propertyName>()的格式命名。
【使用ObjectAnimator实现动画】
-
关于使用ObjectAnimator实现动画的步骤和实践
1.通过调用ofFloat()、ofInt()等方法创建ObjectAnimator对象,并设置目标对象、需要改变的目标属性名、初始值和结束值;
2.设置动画的持续时间、是否重复及重复次数等属性;
3.启动动画。
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();
1 . 第一个参数:设置目标对象,即操纵的view
2 . 第二个参数:设置操作的动画的属性值(见上面讲解的动画属性值)
3 . 第三个参数:可变数组参数 (初始值,中间值,结束值)。可以有一个到N个,如果是一个值的话默认这个值是动画过渡值的结束值。如果有N个值,动画就在这N个值之间过渡。
【使用ValueAnimator实现动画】
-
关于使用ValueAnimator实现动画的步骤及实践
那一般使用ValueAnimator实现动画分为以下七个步骤:
1. 调用ValueAnimation类中的ofInt(int...values)、ofFloat(String propertyName,float...values)等静态方法实例化ValueAnimator对象,并设置目标属性的属性名、初始值或结束值等值;
2.调用addUpdateListener(AnimatorUpdateListener mListener)方法为ValueAnimator对象设置属性变化的监听器;
3.创建自定义的Interpolator,调用setInterpolator(TimeInterpolator value)为ValueAniamtor设置自定义的Interpolator;(可选,不设置默认为缺省值)
4.创建自定义的TypeEvaluator,调用setEvaluator(TypeEvaluator value)为ValueAnimator设置自定义的TypeEvaluator;(可选,不设置默认为缺省值)
5.在AnimatorUpdateListener 中的实现方法为目标对象的属性设置计算好的属性值。
6.设置动画的持续时间、是否重复及重复次数等属性;
7.为ValueAnimator设置目标对象并开始执行动画。
【ObjectAnimator和ValueAnimator的对比】
- ObjectAnimator类作为ValueAnimator的子类不仅继承了ValueAnimator的所有方法和特性,并且还封装很多实用的方法,方便开发人员快速实现动画。
- ObjectAnimator属性值会自动更新,使用ObjectAnimator实现动画不需要像ValueAnimator那样必须实现 ValueAnimator.AnimatorUpdateListener ,因此实现任意对象的动画显示就更加容易了。
- ValueAnimator并没有在属性上做操作,不需要操作的对象的属性一定要有getter和setter方法,你可以自己根据当前动画的计算值,来操作任何属性。
【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动画集合】
可以调用其playTogether(同时执行)、playSequentially(顺序执行)、play、before、with、after 等方法设置动画的执行顺序,然后调用其start 触发动画执行。
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 和 AnimationSet 区别
AnimationSet 与 AnimatorSet 最大的不同在于:
AnimationSet 使用的是 Animation 子类、AnimatorSet 使用的是 Animator 的子类。
-----Animation 是针对视图外观的动画实现,动画被应用时外观改变但视图的触发点不会发生变化,还是在原来定义的位置。 (也就是作用于视图动画)
-----Animator 是针对视图属性的动画实现,动画被应用时对象属性产生变化,最终导致视图外观变化。(也就是作用于属性动画)
AnimatorSet 和 PropertyValuesHolder 区别
--- AnimatorSet可以将作用于多个view多个属性的动画集合起来,而PropertyValuesHolder针对同一个对象多个属性。
--- AnimatorSet多了playTogether(同时执行)、playSequentially(顺序执行)、play(objectAnimator1).with(objectAnimator2)、before、after这些方法协同工作。
【关于View的animate方法】
Android 3.0后,谷歌给View增加animate方法直接驱动属性动画。
可以直接这样写就完成了imageview 的透明度有1-0.5以及位置移动到300动画:
imageView.animate()
.alpha(0.5f)
.y(300)
.setDuration(2000);
此后在SDK12,SDK16又分别添加了withStartAction和withEndAction用于在动画前,和动画后执行一些操作。
当然也可以.setListener(listener)等操作
imageView.animate()//
.alpha(0)// 由1到0
.y(mScreenHeight / 2)
.setDuration(1000)
// need API 12
.withStartAction(new Runnable()
{
@Override
public void run()
{
}
// need API 16
}).withEndAction(new Runnable()
{
@Override
public void run()
{
runOnUiThread(new Runnable()
{
@Override
public void run()
{
imageView.setY(0);
imageView.setAlpha(1.0f);
}
});
}
}).start();
其实上面的这段操作通过PropertyValuesHolder也可以实现:
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("alpha", 1f,
0f, 1f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 0,
mScreenHeight / 2, 0);
ObjectAnimator.ofPropertyValuesHolder(imageView, pvhX, pvhY).setDuration(1000).start();