0%

Android 动画深入分析(一):View 动画

1. Android 中动画的分类

  • View 动画

    • View 动画通过对场景里的对象不断做图像变换(平移、缩放、旋转、透明度)从而产生动画效果
    • View 动画是一种渐进式动画,并且支持自定义
  • 帧动画

    • 帧动画通过顺序播放一系列图像从而产生动画效果,可以简单理解为图片切换动画
    • 很显然,如果图片过多过大就会导致 OOM。帧动画也属于 View 动画的一种,只不过和平移、旋转等常见的 View 动画在表现形式上略有不同
  • 属性动画

    • 属性动画通过动态改变对象的属性从而达到动画效果
    • 属性动画为 API 11 版本的新特性,在低版本无法直接使用属性动画

2. View 动画的分类

名称 标签 子类 效果
平移动画 <translate TranslateAnimation 移动 View
缩放动画 <scale> ScaleAnimation 缩放 View
旋转动画 <rotate> RotateAnimation 旋转 View
透明度动画 <alpha> AlphaAnimation 改变 View 的透明度

3. View 动画 XML 语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?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>
  • View 动画既可以是单个动画,也可以由一系列动画组成

  • <set> 标签表示动画集合,对应 AnimationSet 类,它可以包含若干个动画,并且它的内部也是可以嵌套其他动画集合。两个属性含义如下:

    属性 含义
    android:interpolator 表示动画集合所采用的插值器,插值器影响动画的速度,比如非匀速动画就需要通过插值器来控制动画的播放过程。这个属性可以不指定,默认为 @android:anim/accelerate_decelerate_interpolator,即加速减速插值器
    android:shareInterpolator 表示集合中的动画是否和集合共享同一个插值器。如果集合不指定插值器,那么子动画就需要单独指定所需的插值器或者使用默认值
    • <translate> 标签:表示平移动画,对应 TranslateAnimation 类,它可以是一个 View 在水平和竖直方向完成平移的动画效果。其属性含义如下:

      属性 含义
      android:fromXDelta 表示 x 的起始值,比如 0
      android:toXDelta 表示 x 的结束值,比如 100
      android:fromYDelta 表示 y 的起始值
      android:toYDelta 表示 y 的结束值
    • <scale> 标签:表示缩放动画,对应 ScaleAnimation 类,它可以使 View 具有放大或缩小的动画效果。其属性含义如下:

      属性 含义
      android:fromXScale 水平方向缩放的起始值,比如 0.5
      android:toXScale 水平方向缩放的结束值,比如 1.2
      android:fromYScale 竖直方向缩放的起始值
      android:toYScale 竖直方向缩放的结束值
      android:pivotX 缩放的轴点的 x 坐标,它会影响缩放的效果
      android:pivotY 缩放的轴点的 y 坐标,它会影响缩放的效果
      • 轴点:默认情况下轴点是 View 的中心点,此时在水平方向进行缩放会导致 View 向左右两个方向同时进行缩放。如果把轴点设为 View 的右边界,那么 View 就只会向左边进行缩放,反之则向右边进行缩放
    • <rotate> 标签:表示旋转动画,对应于 RotateAnimation 类,它可以使 View 具有旋转的动画效果。其属性含义如下:

      属性 含义
      android:fromDegrees 旋转开始的角度,比如 0
      android:toDegrees 旋转结束的角度,比如 180
      android:pivotX 旋转的轴点的 x 坐标
      android:pivotY 旋转的轴点的 y 坐标
      • 轴点:在旋转动画中,轴点扮演着旋转轴的角色,即 View 是围绕着轴点进行旋转的,默认情况下轴点为 View 的中心点
    • <alpha> 标签:表示透明度动画,对应 AlphaAnimation 类,它可以改变 View 的透明度。其属性含义如下:

      属性 含义
      android:fromAlpha 表示透明度的起始值,比如 0.1
      android:toAlpha 表示透明度的结束值,比如 1
  • View 动画还有一些常用的属性,如下:

    属性 含义
    android:duration 动画的持续时间
    android:fillAfter 动画结束以后 View 是否停留在结束位置
  • 通过 Animation 的 setAnimationListener() 方法可以给 View 动画添加过程监听。接口如下:

    1
    2
    3
    4
    5
    public static interface AnimationListener {
    void onAnimationStart(Animation animation);
    void onAnimationEnd(Animation animation);
    void onAnimationRepeat(Animation animation);
    }

4. 自定义 View 动画

  • 简单的方面,派生一种新动画只需要继承 Animation 这个抽象类,然后重写 initialize()applyTransformation() 方法。在 initialize() 方法中做一些初始化工作,在 applyTransformation() 方法中进行相应的矩阵变换即可,很多时候需要采用 Camera 来简化矩阵变换的过程

  • 复杂的方面,自定义 View 动画的过程主要是矩阵变换的过程,矩阵变换涉及到数学上的概念和操作

  • Demo:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    	// 来自于 Android 的 ApiDemos 中的一个自定义 View 动画 Rotate3dAnimation(可以围绕 y 轴旋转并且同时沿着 z 轴平移从而实现一种类似于 3D 的效果)
    public class Rotate3dAnimation extends Animation {
    private final float mFromDegrees;
    private final float mToDegrees;
    private final float mCenterX;
    private final float mCenterY;
    private final float mDepthZ;
    private final boolean mReverse;
    private Camera mCamera;

    public Rotate3dAnimation(float fromDegrees, float toDegrees, float centerX, float centerY, float depthZ, boolean reverse) {
    mFromDegrees = fromDegrees;
    mToDegrees = toDegrees;
    mCenterX = centerX;
    mCenterY = centerY;
    mDepthZ = depthZ;
    mReverse = reverse;
    }

    @Override
    public void initialize(int width, int height, int parentWidth, int parentHeight) {
    super.initialize(width, height, parentWidth, parentHeight);
    mCamera = new Camera();
    }

    @Override
    protected void applyTransformation(float interpolatedTime, Transformation t) {
    final float fromDegrees = mFromDegrees;
    float degrees = fromDegrees + ((mToDegrees - fromDegrees) * interpolatedTime);
    final float centerX = mCenterX;
    final float centerY = mCenterY;
    final Camera camera = mCamera;
    final Matrix matrix = t.getMatrix();

    camera.save();

    if(mReverse) {
    camera.translate(0.0f, 0.0f, mDepthZ * interpolatedTime);
    } else {
    camera.translate(0.0f, 0.0f, mDepthZ * (1.0f - interpolatedTime));
    }
    camera.rotateY(degrees);
    camera.getMatrix(matrix);
    camera.restore();

    matrix.preTranslate(-centerX, -centerY);
    1. 1. 1. 1. matrix.postTranslate(centerX, centerY);
    }
    }
    • 实际开发中很少用到自定义 View 动画

5. 帧动画

  • 帧动画是顺序播放一组预先定义好的图片,类似于电影播放

  • 系统提供了类 AnimationDrawable 来使用帧动画

  • Demo:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 通过 XML 定义一个 AnimationDrawable
    // res/drawable/frame_animation.xml
    <?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/image1" android:duration="500" />
    <item android:drawable="@drawable/image2" android:duration="500" />
    <item android:drawable="@drawable/image3" android:duration="500" />
    </animation-list>
    1
    2
    3
    4
    5
    // 设置并使用 AnimationDrawable
    Button mButton = (Button) findViewById(R.id.button1);
    mButton.setBackgroundResource(R.drawable.frame_animation);
    AnimationDrawable drawable = (AnimationDrawable) mButton.getBackground();
    drawable.start();
    • 帧动画的使用比较简单,但比较容易引起 OOM,所以在使用帧动画时应尽量避免使用过多尺寸较大的图片
-------------------- 本文结束感谢您的阅读 --------------------