LayoutAnimationController介绍

你或许注意到android.view.animation包下有个类很特别的类叫LayoutAnimationController

LayoutAnimationController介绍

AlphaAnimation等类不同,LayoutAnimationController并不是Animation的子类。先看看官方文档。

A layout animation controller is used to animated a layout’s, or a view group’s, children. Each child uses the same animation but for every one of them, the animation starts at a different time. A layout animation controller is used by ViewGroup to compute the delay by which each child’s animation start must be offset. The delay is computed by using characteristics of each child, like its index in the view group. This standard implementation computes the delay by multiplying a fixed amount of miliseconds by the index of the child in its parent view group. Subclasses are supposed to override getDelayForView(android.view.View) to implement a different way of computing the delay. For instance, a GridLayoutAnimationController will compute the delay based on the column and row indices of the child in its parent view group. Information used to compute the animation delay of each child are stored in an instance of LayoutAnimationController.AnimationParameters, itself stored in the ViewGroup.LayoutParams of the view

简单来说就是,ViewGroup使用LayoutAnimationController来计算子View动画的延迟时间。通常使用子View的某个特征来计算延迟时间,比如子View的索引。标准实现中是使用子View的索引乘上一个固定的时间。LayoutAnimationController的子类也可以重写getDelayForView()方法,以使用其它计算方式。比如GridLayoutAnimationController就是基于行索引和列索引来计算子View的动画的延迟时间。

用于计算每个子View动画延迟时间的信息保存在LayoutAnimationController.AnimationParameters参数中,而该参数本身又保存在ViewGroup.LayoutParams中。

LayoutAnimationController用法

它的用法还是比较简单,所以直接上例子。

rv_item_list_anim.xml用于指定item的动画。

1
2
3
4
5
6
7
8
9
10
11
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="1000"
android:shareInterpolator="true">
<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0" />
<translate
android:fromXDelta="-100%"
android:toXDelta="0%" />
</set>

rv_layout_animation.xml用于定义LayoutAnimationController。

1
2
3
4
5
6
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
android:animation="@anim/rv_item_list_anim"
android:animationOrder="normal"
android:delay="0.2"
android:interpolator="@android:anim/linear_interpolator" />

效果如下:

LayoutAnimationController源码分析

ViewGroup使用LayoutAnimationController成员来实现动画效果。相关的方法包括:

  • setLayoutAnimation()getLayoutAnimation() - 分别用于设置和获取动画
  • canAnimate() - 判断是否有动画效果
  • startLayoutAnimation() - 启动动画
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
public abstract class ViewGroup extends View implements ViewParent, ViewManager {

// Layout animation
private LayoutAnimationController mLayoutAnimationController;
private Animation.AnimationListener mAnimationListener;

/**
* Returns the layout animation controller used to animate the group's
* children.
*
* @return the current animation controller
*/
public LayoutAnimationController getLayoutAnimation() {
return mLayoutAnimationController;
}

/**
* Sets the layout animation controller used to animate the group's
* children after the first layout.
*
* @param controller the animation controller
*/
public void setLayoutAnimation(LayoutAnimationController controller) {
mLayoutAnimationController = controller;
if (mLayoutAnimationController != null) {
mGroupFlags |= FLAG_RUN_ANIMATION;
}
}

/**
* Indicates whether the view group has the ability to animate its children
* after the first layout.
*
* @return true if the children can be animated, false otherwise
*/
protected boolean canAnimate() {
return mLayoutAnimationController != null;
}

/**
* Runs the layout animation. Calling this method triggers a relayout of
* this view group.
*/
public void startLayoutAnimation() {
if (mLayoutAnimationController != null) {
mGroupFlags |= FLAG_RUN_ANIMATION;
requestLayout();
}
}

LayoutAnimationController的时序图如下:

对几个关键步骤稍加说明:

  • 第5步 - 调用LayoutAnimationController.getAnimationForView()为child view创建animation
  • 第6步 - 调用LayoutAnimationController.start()启动动画
  • 第8步 - 注意这一步调用的是boolean View.draw(Canvas canvas, ViewGroup parent, long drawingTime)方法。所以其实最终又回到了前一篇所讲的View Animation