1、概述
Android的动画分为三种,View Animation(视图动画)、 Drawable Animation(帧动画)、Property Animation(属性动画)。其实Drawable Animation(帧动画)也属于View Animation(视图动画)的一种,只不过它和View动画的表现形式不同。
View动画通过对场景里的图像不断做图像变换(平移、缩放、旋转、透明度)从而产生动画效果,它是一种渐进式动画,并且View动画支持自定义。
帧动画通过顺序播放一系列图像从而产生动画效果,可简单理解为图片切换动画,但是,如果图片够多过大就会引起OOM(out of memory)。
Property Animation(属性动画)通过动态的改变对象的属性来达到动画效果,属性动画为API 11新特性,在低版本无法直接使用,但是通过兼容库nineoldandroids来使用。
2、View Animation(视图动画)
View动画的作用对象是 View,它支持四种动画效果,平移动画、缩放动画、旋转动画和透明度动画,它只改变View的绘制效果,而实际属性值未变。例如,动画移动了一个按钮位置,但按钮的实际点击位置不变。
(1)View动画的四种变换
(2)Animation通用属性详解
(3)Translate属性详解
(4)Scale属性详解
(5)Rotate属性详解
(6)Alpha属性详解
(7)插值器
插值器影响动画的速度,各种插值器实现了Interpolator接口。
插值器使用方法:
<set android:interpolator="@android:anim/accelerate_interpolator">
...
</set>
(8)使用方法
这四种动画既可以通过XML来定义,也可以通过代码动态创建,对于View动画来说,建议采用XML定义,因为可读性好。
XML定义:
<?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>
java程序调用:
mButton = (Button) findViewById(R.id.btn_animation);
Animation animation = AnimationUtils.loadAnimation(this,R.anim.test_animation);
mButton.startAnimation(animation);
3、Drawable Animation(帧动画)
帧动画是播放一组预先定义好的图片,类似于电影播放。系统使用AnimationDrawable类来使用帧动画。
(1)通过在drawable中的XML定义一个AnimationDrawable。
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="@drawable/my1" android:duration="500"></item>
<item android:drawable="@drawable/my2" android:duration="500"></item>
<item android:drawable="@drawable/my3" android:duration="500"></item>
<item android:drawable="@drawable/my4" android:duration="500"></item>
</animation-list>
(2)将上述Drawable作为View背景并通过Drawable来播放动画。
mButton = (Button) findViewById(R.id.btn_animation);
mButton.setBackgroundResource(R.drawable.drawable_animation);
AnimationDrawable drawable = (AnimationDrawable) mButton.getBackground();
drawable.start();
4、Property Animation(属性动画)
动画的对象除了传统的View对象,还可以是Object对象,动画之后,Object对象的属性值被实实在在的改变了。Property animation能够通过改变View对象的实际属性来实现View动画。任何时候View属性的改变,View能自动调用invalidate()来试试刷新。重点:属性动画实现原理就是修改控件的属性值实现的动画。
属性动画重点类:
Android属性动画(注意最低兼容版本,不过可以使用开源项目来替代低版本问题)提供了以下属性:
Duration:动画的持续时间;
TimeInterpolation:定义动画变化速率的接口,所有插值器都必须实现此接口,如线性、非线性插值器;
TypeEvaluator:用于定义属性值计算方式的接口,有int、float、color类型,根据属性的起始、结束值和插值一起计算出当前时间的属性值;
Animation sets:动画集合,即可以同时对一个对象应用多个动画,这些动画可以同时播放也可以对不同动画设置不同的延迟;
Frame refreash delay:多少时间刷新一次,即每隔多少时间计算一次属性值,默认为10ms,最终刷新时间还受系统进程调度与硬件的影响;
Repeat Country and behavoir:重复次数与方式,如播放3次、5次、无限循环,可以让此动画一直重复,或播放完时向反向播放;
(1)XML方式属性动画
在xml中可直接用的属性动画节点有ValueAnimator、ObjectAnimator、AnimatorSet。
<set
android:ordering=["together" | "sequentially"]>
<objectAnimator
android:propertyName="string"
android:duration="int"
android:valueFrom="float | int | color"
android:valueTo="float | int | color"
android:startOffset="int"
android:repeatCount="int"
android:repeatMode=["repeat" | "reverse"]
android:valueType=["intType" | "floatType"]/>
<animator
android:duration="int"
android:valueFrom="float | int | color"
android:valueTo="float | int | color"
android:startOffset="int"
android:repeatCount="int"
android:repeatMode=["repeat" | "reverse"]
android:valueType=["intType" | "floatType"]/>
<set>
...
</set>
</set>
< set>属性解释
< objectAnimator>属性解释
XML属性动画使用方法
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
R.animtor.property_animator);
set.setTarget(myObject);
set.start();
(2)java方式属性动画
1、ObjectAnimator:继承自ValueAnimator,允许你指定要进行动画的对象以及该对象 的一个属性。该类会根据计算得到的新值自动更新属性。大多数的情况使用ObjectAnimator就足够了,因为它使得目标对象动画值的处理过程变得足 够简单,不用像ValueAnimator那样自己写动画更新的逻辑,但是ObjectAnimator有一定的限制,比如它需要目标对象的属性提供指定 的处理方法(譬如提供getXXX,setXXX方法),这时候你就需要根据自己的需求在ObjectAnimator和ValueAnimator中看 哪种实现更方便了。
ObjectAnimator类提供了ofInt、ofFloat、ofObject这个三个常用的方法,这些方法都是设置动画作用的元素、属性、开始、结束等任意属性值。当属性值(上面方法的参数)只设置一个时就把通过getXXX反射获取的值作为起点,设置的值作为终点;如果设置两个(参数),那么一个是开始、另一个是结束。
特别注意:ObjectAnimator的动画原理是不停的调用setXXX方法更新属性值,所有使用ObjectAnimator更新属性时的前提是Object必须声明有getXXX和setXXX方法。
我们通常使用ObjectAnimator设置View已知的属性来生成动画,而一般View已知属性变化时都会主动触发重绘图操作,所以动画会自 动实现;但是也有特殊情况,譬如作用Object不是View,或者作用的属性没有触发重绘,或者我们在重绘时需要做自己的操作,那都可以通过如下方法手动设置:
ObjectAnimator mObjectAnimator= ObjectAnimator.ofInt(view, "customerDefineAnyThingName", 0, 1).setDuration(2000);
mObjectAnimator.addUpdateListener(new AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
//int value = animation.getAnimatedValue(); 可以获取当前属性值
//view.postInvalidate(); 可以主动刷新
//view.setXXX(value);
//view.setXXX(value);
//......可以批量修改属性
}
});
如下是一个Y轴3D旋转动画实现实例:
ObjectAnimator.ofFloat(view, "rotationY", 0.0f, 360.0f).setDuration(1000).start();
2、PropertyValuesHolder:多属性动画同时工作管理类。有时候我们需要同时修改多个属性,那就可以用到此类,具体如下:
PropertyValuesHolder a1 = PropertyValuesHolder.ofFloat("alpha", 0f, 1f);
PropertyValuesHolder a2 = PropertyValuesHolder.ofFloat("translationY", 0, viewWidth);
......
ObjectAnimator.ofPropertyValuesHolder(view, a1, a2, ......).setDuration(1000).start();
如上代码就可以实现同时修改多个属性的动画啦。
3、ValueAnimator:属性动画中的时间驱动,管理着动画时间的开始、结束属性值,相应时间属性值计算方法等。包含所有计算动画值的核心函数以及每一个动画时间节点上的信息、一个动画是否重复、是否监听更新事件等,并且还可以设置自定义的计算类型。
特别注意:ValueAnimator只是动画计算管理驱动,设置了作用目标,但没有设置属性,需要通过updateListener里设置属性才会生效。
ValueAnimator animator = ValueAnimator.ofFloat(0, mContentHeight); //定义动画
animator.setTarget(view); //设置作用目标
animator.setDuration(5000).start();
animator.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation){
float value = (float) animation.getAnimatedValue();
view.setXXX(value); //必须通过这里设置属性值才有效
view.mXXX = value; //不需要setXXX属性方法
}
});
大眼看上去可以发现和ObjectAnimator没啥区别,实际上正是由于ValueAnimator不直接操作属性值,所以要操作对象的属性可以不需要setXXX与getXXX方法,你完全可以通过当前动画的计算去修改任何属性。
4、AnimationSet:动画集合,提供把多个动画组合成一个组合的机制,并可设置动画的时序关系,如同时播放、顺序播放或延迟播放。具体使用方法比较简单,如下:
ObjectAnimator a1 = ObjectAnimator.ofFloat(view, "alpha", 1.0f, 0f);
ObjectAnimator a2 = ObjectAnimator.ofFloat(view, "translationY", 0f, viewWidth);
......
AnimatorSet animSet = new AnimatorSet();
animSet.setDuration(5000);
animSet.setInterpolator(new LinearInterpolator());
//animSet.playTogether(a1, a2, ...); //两个动画同时执行
animSet.play(a1).after(a2); //先后执行
......//其他组合方式
animSet.start();
5、Evaluators相关类解释: Evaluators就是属性动画系统如何去计算一个属性值。它们通过Animator提供的动画的起始和结束值去计算一个动画的属性值。
IntEvaluator:整数属性值。
FloatEvaluator:浮点数属性值。
ArgbEvaluator:十六进制color属性值。
TypeEvaluator:用户自定义属性值接口,譬如对象属性值类型不是int、float、color类型,你必须实现这个接口去定义自己的数据类型。
既然说到这了,那就来个例子吧,譬如我们需要实现一个自定义属性类型和计算规则的属性动画,如下类型float[]:
ValueAnimator valueAnimator = new ValueAnimator();
valueAnimator.setDuration(5000);
valueAnimator.setObjectValues(new float[2]); //设置属性值类型
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.setEvaluator(new TypeEvaluator<float[]>()
{
@Override
public float[] evaluate(float fraction, float[] startValue,
float[] endValue)
{
//实现自定义规则计算的float[]类型的属性值
float[] temp = new float[2];
temp[0] = fraction * 2;
temp[1] = (float)Math.random() * 10 * fraction;
return temp;
}
});
valueAnimator.start();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
float[] xyPos = (float[]) animation.getAnimatedValue();
view.setHeight(xyPos[0]); //通过属性值设置View属性动画
view.setWidth(xyPos[1]); //通过属性值设置View属性动画
}
});
6、Interpolators相关类解释:
AccelerateDecelerateInterolator:先加速后减速。
AccelerateInterpolator:加速。
DecelerateInterpolator:减速。
AnticipateInterpolator:先向相反方向改变一段再加速播放。
AnticipateOvershootInterpolator:先向相反方向改变,再加速播放,会超出目标值然后缓慢移动至目标值,类似于弹簧回弹。
BounceInterpolator:快到目标值时值会跳跃。
CycleIinterpolator:动画循环一定次数,值的改变为一正弦函数:Math.sin(2 * mCycles * Math.PI * input)。
LinearInterpolator:线性均匀改变。
OvershottInterpolator:最后超出目标值然后缓慢改变到目标值。
TimeInterpolator:一个允许自定义Interpolator的接口,以上都实现了该接口。
7、Java属性动画拓展之ViewPropertyAnimator动画
在Android API 12时,View中添加了animate方法,具体如下:
public class View implements Drawable.Callback, KeyEvent.Callback,
AccessibilityEventSource {
......
/**
* This method returns a ViewPropertyAnimator object, which can be used to animate
* specific properties on this View.
*
* @return ViewPropertyAnimator The ViewPropertyAnimator associated with this View.
*/
public ViewPropertyAnimator animate() {
if (mAnimator == null) {
mAnimator = new ViewPropertyAnimator(this);
}
return mAnimator;
}
......
}
可以看见通过View的animate()方法可以得到一个ViewPropertyAnimator的属性动画(有人说他没有继承Animator类,是的,他是成员关系,不是之前那种继承关系)。
ViewPropertyAnimator提供了一种非常方便的方法为View的部分属性设置动画(切记,是部分属性),它可以直接使用一个 Animator对象设置多个属性的动画;在多属性设置动画时,它比 上面的ObjectAnimator更加牛逼、高效,因为他会管理多个属性的invalidate方法统一调运触发,而不像上面分别调用,所以还会有一些 性能优化。如下就是一个例子:
myView.animate().x(0f).y(100f).start();
8、Java属性动画拓展之LayoutAnimator容器布局动画
Property动画系统还提供了对ViewGroup中View添加时的动画功能,我们可以用LayoutTransition对 ViewGroup中的View进行动画设置显示。LayoutTransition的动画效果都是设置给ViewGroup,然后当被设置动画的 ViewGroup中添加删除View时体现出来。该类用于当前布局容器中有View添加、删除、隐藏、显示等时候定义布局容器自身的动画和View的动 画,也就是说当在一个LinerLayout中隐藏一个View的时候,我们可以自定义 整个由于LinerLayout隐藏View而改变的动画,同时还可以自定义被隐藏的View自己消失时候的动画等。
我们可以发现LayoutTransition类中主要有五种容器转换动画类型,具体如下:
LayoutTransition.APPEARING:当View出现或者添加的时候View出现的动画。
LayoutTransition.CHANGE_APPEARING:当添加View导致布局容器改变的时候整个布局容器的动画。
LayoutTransition.DISAPPEARING:当View消失或者隐藏的时候View消失的动画。
LayoutTransition.CHANGE_DISAPPEARING:当删除或者隐藏View导致布局容器改变的时候整个布局容器的动画。
LayoutTransition.CHANGE:当不是由于View出现或消失造成对其他View位置造成改变的时候整个布局容器的动画。
XML方式使用系统提供的默认LayoutTransition动画:
我们可以通过如下方式使用系统提供的默认ViewGroup的LayoutTransition动画:
android:animateLayoutChanges=”true”
在ViewGroup添加如上xml属性默认是没有任何动画效果的,因为前面说了,该动画针对于ViewGroup内部东东发生改变时才有效,所以当我们设置如上属性然后调运ViewGroup的addView、removeView方法时就能看见系统默认的动画效果了。
还有一种就是通过如下方式设置:
android:layoutAnimation=”@anim/customer_anim”
通过这种方式就能实现很多吊炸天的动画。
Java方式使用系统提供的默认LayoutTransition动画:
在使用LayoutTransition时,你可以自定义这几种事件类型的动画,也可以使用默认的动画,总之最终都是通过 setLayoutTransition(LayoutTransition lt)方法把这些动画以一个LayoutTransition对象设置给一个ViewGroup。
譬如实现如上Xml方式的默认系统LayoutTransition动画如下:
mTransitioner = new LayoutTransition();
mViewGroup.setLayoutTransition(mTransitioner);
稍微再高端一点吧,我们来自定义这几类事件的动画,分别实现他们,那么你可以像下面这么处理:
mTransitioner = new LayoutTransition();
......
ObjectAnimator anim = ObjectAnimator.ofFloat(this, "scaleX", 0, 1);
......//设置更多动画
mTransition.setAnimator(LayoutTransition.APPEARING, anim);
......//设置更多类型的动画 mViewGroup.setLayoutTransition(mTransitioner);
到此通过LayoutTransition你就能实现类似小米手机计算器切换普通型和科学型的炫酷动画了。
5、Android动画总结
到此Android动画基本已经描述OK了,也就这么三大类,尤其是属性动画更加一筹。但是特别说一句,上面基本都没有提及到各种动画的 Listener接口,原因是这个玩意太简单,所以不提了,相信你会监听View的onClickListener就一定会触类旁通动画的 Listener方法的。有了这些基础相信无论是自定义控件时还是自定义动画时都会起到直接的指导参考作用。其实对于Android的动画实现远远不止现 在提到的这些,但是这些又是基础,所以后面还会写文章说说Android提供的其他动画参考工具类的。
区别:
View动画:
View动画只能够为View添加动画,如果想为非View对象添加动画须自己实现;且View动画支持的种类很少;尤其是他改变的是View的绘制效果,View的属性没有改变,其位置与大小都不变; View动画代码量少,使用简单方便。
Property动画:
弥补了View动画的缺陷,你可以为一个对象的任意属性添加动画,对象自己的属性会被真的改变;当对象的属性变化的时候,属性动画会自动刷新屏幕;属性动画改变的是对象的真实属性,而且属性动画不止用于View,还可以用于任何对象。