Android开发艺术探索:Android动画深入分析

View动画(View Animation)

具有四种动画效果:平移,缩放,旋转,透明度,分别对应类为TranslateAnimation,ScaleAnimation,RotateAnimation,AlphaAnimation,对应的xml标签为,View动画一般使用xml来创建,在/res/anim/your_name.xml,保证可读性,自定义View推荐使用代码,View动画并不会真正改变View的属性,只是一个影像,并且Android系统提供的动画效果只有这几种,如果想要功能丰富的动画并且改变属性,应该使用属性动画( Property 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"]
    android:fillAfter="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>
Button mButton = (Button)findViewById(R.id.bt);
Animation animation = AnimationUtils.loadAnimation(context,R.anim.your_filename.xml);
mButton.startAnimation(animation);

可以为View动画添加动画监听器setAnimationListener。

自定义View 3D动画,一般继承Animation并采用Camera来简化矩阵变化,ApiDemo里面有相关实例。

帧动画 Drawable Animation

顺序播放一组自定义好的图片

<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="true">
    <item android:drawable="@drawable/rocket_thrust1" android:duration="200" />
    <item android:drawable="@drawable/rocket_thrust2" android:duration="200" />
    <item android:drawable="@drawable/rocket_thrust3" android:duration="200" />
</animation-list>

ImageView rocketImage = (ImageView) findViewById(R.id.rocket_image);
rocketImage.setBackgroundResource(R.drawable.rocket_thrust);
rocketAnimation = (AnimationDrawable) rocketImage.getBackground();
rocketAnimation.start();

帧动画使用过多尺寸较大的图片容易出现OOM。

View动画特殊使用场景

/res/anim/your_filename.xml

<LayoutAnimation
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:delay="0.5"
    android:animationOrder="normal"
    android:anmition="@anim/anim_item"
    />

为支持LayoutAnimation的ViewGoup指定android:layoutAnimation=”@anim/anim_layout”,也可以在代码中设置。

ListView listView = (ListView)findViewById(R.id.list);
Animation animation = AnumationUtils.loadAnimation(context,R.anim.anim_item);
LayoutAnimationController controller = new LayoutAnimationController();
controller.setDelay(0.5f);
controller.setOrder(LayoutAnimationController.ORDER_NOMAL);
listView.setLayoutAnimation(controller);

overridePendingTransition(int enterAnim,int exitAnim) ,这个方法必须在startActivity(intent)或者finish()之后才能生效。

属性动画 Property Animation

属性动画默认时间间隔300ms,默认帧率为10ms/帧。
实质是使用插值器(Interpolator)和估值器(Evalutor),计算某一时刻View的属性的值,主要使用的类有ValueAnimator,ObjectAnimator,AnimatorSet。

TimeInterpolator 根据事件流逝的百分比来计算出当前属性值改变的百分比。
TypeEvaluator 根据当前属性改变的百分比来计算改变后的属性值。

AnimatorListener/AnimatorListenerAdapter监听动画的开始,结束,取消,重复播放,AnimatorUpdateListener监听整个动画过程,没播放一帧就会被调用一次。

ObjectAnimator 可以方便地完成动画效果:

//没有指定插值器的话,默认使用的是AccelerateDecelerateInterpolator
public void performAnimation(View view) {
    ObjectAnimator.ofFloat(view,"x",0,500).setDuration(1000).start();
}

使用 ValueAnimator 同样可以完成相同的工作,只是需要我们去手动地改变我们属性的值:

public void performAnimation(final View view) {
    ValueAnimator valueAnimator = ValueAnimator.ofFloat(500f).setDuration(1000);
    //可以手动设置估值器,并在AnimatorUpdateListener里面通过animation.getAnimatedValue() 获取
    valueAnimator.setEvaluator(new FloatEvaluator());
    valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            float value = (float)animation.getAnimatedValue();
            view.setX(value);
        }
    });
    valueAnimator.start();
}

使用 Keyframe,来完成:

//第一个参数是动画的完成度,后面的是可变参数
//每个Keyframe都可以指定自己的插值器
Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);
Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation)
rotationAnim.setDuration(5000ms);

对任意属性XXX做动画:

setX与setTranslationX区别:x就是单纯的位置,包含了子View到父View的左边距(例如marginLeft),translationX是View移动的距离

多个动画组合:

ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();

属性动画官方文档

使用动画注意事项