Android的动画有三种:View动画、帧动画和属性动画
一、View动画
View动画是对View的影像做改变,并不是真的改变View的状态
1、View动画的种类
共有四种,分别对应着Animation的四个子类及XML文件中的四种标签
名称 子类 标签 平移动画 TranslateAnimation <translate>
缩放动画 ScaleAnimation <scale>
旋转动画 RotateAnimation <rotate>
透明度动画 AlphaAnimation <alpha>
XML文件的位置
res/anim/filename.xml
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:interpolator="@android:anim/accelerate_decelerate_interpolator" android:shareInterpolator="true" > <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>
android:interpolator=”@android:anim/accelerate_decelerate_interpolator”
- 表示动画集合所采用的插值器。
- 用于控制动画的速度。
- 可以不指定,默认为加速减速插值器
- android:shareInterpolator=”true”
- 表示集合中的动画是否和集合共享同一个插值器
- 如果集合不指定插值器,那么子动画就要单独指定或使用默认值
<alpha>
- android:fromAlpha:表示透明度的起始值,eg:0.1
- android:toAlpha:表示透明度的结束值,eg:1
<scale>
- android:fromXScale:水平方向的缩放起始值,比如0.5
- android:toXScale:水平方向缩放的结束值,比如1.2
- android:fromYScale:竖直方向的缩放起始值
- android:toYScale:竖直方向缩放的结束值
- android:pivotX:缩放的轴点的x坐标,会影响缩放的效果(默认轴点为View的中心)
- android:pivotY:缩放的轴点的y坐标,会影响缩放的效果(默认轴点为View的中心)
<translate>
- android:fromXDelta:表示x方向平移的起始值,比如0
- android:toXDelta:表示x方向平移的结束值,比如100
- android:fromYDelta:表示y方向平移的起始值
- android:toYDelta:表示y方向平移的结束值
<rotate>
- android:fromDegrees:旋转开始的角度,比如0
- android:toDegrees:旋转结束的角度,比如180
- android:pivotX:旋转的轴点的x坐标(默认轴点为View的中心)
- android:pivotY:旋转的轴点的y坐标(默认轴点为View的中心)
android:duration:动画的持续时间
- android:fillAfter:动画结束后View是否停留在结束的位置
另外可以通过实例化对应的动画子类对象来设置动画属性
//透明度动画 AlphaAnimation alphaAnimation = new AlphaAnimation(0, 1); alphaAnimation.setDuration(300); //设置动画持续时间为300ms
使用
Button button = (button) findViewById(R.id.button) Animation animation = AnimationUtils.loadAnimation(this, R.anim.animation_test); button.startAnimation(animation);
- 通过Animaiton的setAnimationListener方法对View动画添加过程监听
public static interface AnimationListener {
void onAnimationStart(Animation animation);
void onAnimationEnd(Animation animation);
void onAnimationRepeat(Animation animation);
}
2、自定义View动画
继承Animation抽象类
- (1)重写 initialize 方法:做一些初始化工作
- (2)重写 applyTransformation 方法:进行相应的矩阵变换
- 使用Camera:简化矩阵变换的过程
3、帧动画(Animation Drawable)
顺序播放一组预先定义好的图片
使用:
首先通过xml来定义一个AnimationDrawable,文件位置:res/drawable/filename.xml
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="false" > <item android:drawable="@drawable/image_people" android:duration="500" /> <item android:drawable="@drawable/image_nav_header" android:duration="500" /> <item android:drawable="@drawable/image_white" android:duration="500" /> </animation-list>
然后将上述的Drawable文件作为View的背景通过Drawable来播放动画
button.setBackgroundResource(R.drawable.frame_animation); AnimationDrawable drawable = (AnimationDrawable) button.getBackGround(); drawable.start(); //开始播放
- 使用帧动画容易引起OOM,尽量避免使用过多尺寸较大的图片
二、View动画的特殊使用场景
1、LayoutAnimation
- 作用于ViewGroup。为ViewGroup指定一个动画,这样当它的子元素出场时都会具有这种动画效果。
- eg:使ListView的每个item都以一定的动画出现
使用:
① 定义LayoutAnimation。文件位置:res/anim/filename.xml
<layoutAnimation xmlns:android="http://schemas.andorid.com/apk/res/android" android:delay="0.5" android:animationOrder="normal" android:animation="@anim/anim_item" />
android:delay:子元素开始动画的时间延迟。
- 所设定的数值 * 动画时间周期 = 延迟时间 - 假设子元素时间周期为300ms,此例中第一个子元素延迟150ms出现,第二个子元素延迟300ms出现,以此类推。
- android:animationOrder:动画入场的顺序
- normal:顺序入场
- reverse:逆序入场
- random:随机入场
android:animation:指定子元素具体的入场动画
② 为子元素设置具体的入场动画
- ③ 为ViewGroup指定 android:layoutAnimation
- xml的相应ViewGroup标签下指定
- 通过 LayoutAnimationController 来实现
ListView listView = (ListView) layout.findViewById(R.id.list);
Animation animation = AnimationUtils.loadAnimation(this, R.anim.anim_item);
LayoutAnimationController controller = new LayoutAnimationController(animation);
controller.setDelay(0.5f);
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
listView.setLayoutAnimation(controller);
2、Activity的切换效果
- overridePendingTransition(R.anim.enter_anim, R.anim.exit_anim):设置Activity开场结束动画
- 必须在startActivity(intent)之后或finish()之后调用才有效
- 入场指定
starActivity(intent);
overridePendingTransition(R.anim.enter_anim, R.anim.exit_anim);
- 结束指定
@Override
public void finish() {
super.finish();
overridePendingTransition(R.anim.enter_anim, R.anim.exit_anim);
}
- Fragment添加动画
- 使用support-v4
- 通过 FragmentTransaction的setCustomAnimations()方法 来添加动画
三、属性动画
属性动画要求对象的属性必须要有set方法。
1、基本使用
- 简介:
- 属性动画是API11之后新加入的特性,通过开源动画库nineoldandorids来兼容以前的版本(API11之前的版本是通过代理View动画实现)
- 属性动画可以对任意对象的属性进行动画而不仅仅是View
- 动画默认时间间隔为300ms
- 动画默认帧率为10ms/帧
- 常用类有三个
- (1)ValueAnimator:改变的是值而不一定是具体对象—
<animator>
- (2)ObjectAnimatior:继承自ValueAnimator—
<objectAnimator>
- (2)ObjectAnimatior:继承自ValueAnimator—
- (3)AnimatorSet:动画集合—
<set>
- (1)ValueAnimator:改变的是值而不一定是具体对象—
- 属性动画需要定义在res/animator目录下
通过Java代码定义:(推荐)
ObjectAnimator
//平移 ObjectAnimator.ofFloat(myObject, "translationY", -myObject.getHeight).start();
ValueAnimator
//改变背景色 ValuewAnimator colorAnim = ObjectAnimator.ofInt(this, "backgroundColor", 0*FFFF8080, 0*FF8080FF); colorAnim.setDurtion(3000); colorAnim.setRepeatCount(ValueAnimator.INFINITE); //设置动画无限次循环 colorAnim.setRepeatMode(ValueAnimator.REVERSE); //设置反转效果 corlorAnim.start(); //开始动画
AnimatorSet
AnimatorSet set = new AnimatorSet(); set.playTogether ( ObjectAnimator.ofFloat(myObject, "translationY", -myObject.getHeight()).start(); ObjectAnimator.ofFloat(myObject, "translationX", -myObject.getWidth()).start(); ··· ); set.setDuration(5*1000).start();
通过XML定义:
<?xml version="1.0" encoding="utf-8"?> <set xmlns:android="http://schemas.android.com/apk/res/android" android:ordering="together" > <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="restart | 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="restart | reverse" android:valueType="intType | floatType" /> <set ··· </set> </set>
- android:ordering:动画集合中的子动画播放顺序
- together:默认值。同时播放
- sequentially:顺序播放
- android:propertyName:表示属性动画作用对象的属性的名称
<animator>
没有此属性
- android:duration:表示动画的时长
- android:valueFrom:表示属性的起始值
- android:valueTo:表示属性的结束值
- android:startOffset:表示动画的延迟时间(ms)
- android:repeatCount:表示动画的重复次数
- 0:默认值
- -1:无限次循环
- android:repeatMode:表示动画的重复模式
- restart:连续重复
- reverse:逆向重复(正序、逆序、正序、逆序…)
- android:valueType:表示属性类型
- intType:整型类型
- floatType:浮点型类型
- android:ordering:动画集合中的子动画播放顺序
- 使用:
AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext, R.anim.test_animator);
set.setTarget(button);
set.start();
2、插值器与估值器
实现非匀速动画
- TimeInterpolator(插值器):跟数据时间流逝的百分比来计算出当前属性值改变的百分比
- LinearInterpolator:线性插值器,匀速动画。
- AccelerateDecelerateInterpolator:加速减速插值器,动画两头慢中间快
- DecelerateInterpolator:减速插值器,动画越来越慢
- TypeEvaluator(估值器/类型估值算法):根据当前属性改变的百分比来计算改变后的属性值
- IntEvaluator:针对整型属性
- FloatEvaluator:针对浮点型属性
- 自定义
- 自定义插值器:实现Interpolator或TimeInterpolator接口
- 自定义估值器:实现TypeEvaluator接口
3、属性动画的监听器
- AnimatorListener
- 另外有AnimatorListenerAdapter可以有选择的实现下面的四种方法
public interface AnimatorListener {
void onAnimationStart(Animator animation);
void onAnimationEnd(Animator animation);
void onAnimationCancel(Animator animation);
void onAnimationRepeat(Animator animation);
}
- AnimatorUpdateListener
- 会监听动画的整个过程(即每一帧)
public static interface AnimatorUpdateListener {
void onAnimationUpdate(ValueAnimator animation);
}
4、对任意属性做动画
要求
- object必须提供setAbc方法
- 如果动画的时候没有传递初始值,那么还要提供getAbc方法用于获取abc属性的初始值,否则程序直接Crash
- object的setAbc对属性abc所做的改变必须能够通过某种方法反映出来
- object必须提供setAbc方法
可以用一个类来包装原始对象,间接为其提供get和set方法
private void performAnimate() { ViewWrapper wrapper = new ViewWrapper(mButton); ObjectAnimator.ofInt(wrapper, "width", 500)。setDuration(5000).start(); } @Override public void onClick(View v) { if (v == mButton) { performAnimate(); } } private static class ViewWrapper { private View mTarget; public ViewWrapper(View target) { mTarget = target; } public int getWith() { return mTarget.getLayoutParams().width; } public void setWidth(int width) { mTarget.getLayuoutParamas().width = width; mTarget.requestLayout(); } }
或者可以用ValueAnimator监听动画过程,自己实现属性的改变
//效果与上一种方法一致 private void performAnimate(final View target, final int start, final int end) { ValueAnimator valueAnimator = ValueAnimator.ofInt(1, 100); valueAnimator.addUpdateListener(new AnimatorUpdateListener(){ //持有一个IntEvaluator对象,方便下面估值的时候使用 private IntEvaluator mEvaluator = new IntEvaluator(); @Override public void onAnimationUpdate(ValueAnimator animator) { //获取当前动画的进度值,整型,1-100之间 int currentValue = (Interger) animator.getAnimatedValue(); //获取当前进度占整个动画过程的比例,浮点型,0-1之间 float fraction = animator.getAnimatedFraction(); //直接调用整型估值器,通过比例计算出宽度,然后再设给Button target.getLayoutParams().width = mEvaluator.evaluate(fraction, start, end); target.requestLayout(); } }); valueAnimator.setDuration(5000).start(); } @Override public void onClick(View v) { if (v == mButton) { performAnimate(mButton, mButton.getWidth(), 500); } }
5、属性动画的工作原理
属性动画的原理就是根据外部传入的数值多次调用对象属性的set方法。
- 入口start()
- 需要运行在有Looper的线程中
- 依次调用插值器、估值器来设置属性
- set和get方法均是通过反射来调用的
四、注意事项
- 无限循环动画要在Activity退出时及时停止,否则会内存泄漏。
- View动画完成后View无法隐藏(即setVisibility(View.GONE)失效),调用view.clearAnimation()清除
- 不要使用px