1:LayoutAnimationController用于一个布局或者ViewGroup的动画控制器,它能够让每个子View在不同的时间点分别执行相同的动画,ViewGroup通过LayoutAnimationController计算每个子view的动画开始的时间间隔,这个时间的间隔是通过某种规律特点进行计算,比如它在viewGroup中的index顺序。
- LayoutAnimation_delay:延迟时间
- LayoutAnimation_animationOrder:动画播放顺序
- LayoutAnimation_interpolator:动画的差值,有加速,减速等
- LayoutAnimation_animation:动画的名称
二、动画播放顺序 |
LayoutAnimationController类中对应的播放顺序:
- public static final int ORDER_NORMAL = 0:按照view添加到view group中的顺序进行播放动画展示
- public static final int ORDER_REVERSE = 1;按照view添加到view group中倒叙进行播放动画展示。
- public static final int ORDER_RANDOM = 2;随机顺序播放view的动画。
我们如何构建一个LayoutAnimationController呢?看下它的构造函数。
- public LayoutAnimationController(Context context, AttributeSet attrs)
- public LayoutAnimationController(Animation animation)
- public LayoutAnimationController(Animation animation, float delay)
1、判断两个view之间的动画是否具有重叠,重叠返回true,不重叠返回false
public boolean willOverlap() {
return mDelay < 1.0f;
}
- 1
- 2
- 3
2、启动动画:
public void start() {
mDuration = mAnimation.getDuration();
mMaxDelay = Long.MIN_VALUE;
mAnimation.setStartTime(-1);
}
- 1
- 2
- 3
- 4
- 5
3、获取应用在view上的Animation动画对象:
public final Animation getAnimationForView(View view) {
final long delay = getDelayForView(view) + mAnimation.getStartOffset();
mMaxDelay = Math.max(mMaxDelay, delay);
try {
final Animation animation = mAnimation.clone();
animation.setStartOffset(delay);
return animation;
} catch (CloneNotSupportedException e) {
return null;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
4、判断动画是否完成:所有子view完成动画返回true,否则返回false
public boolean isDone() {
return AnimationUtils.currentAnimationTimeMillis() >
mAnimation.getStartTime() + mMaxDelay + mDuration;
}
5、获取view的动画延迟数:
/**
* 返回view的动画延迟毫秒数,动画一定会延迟,子类需要重写该方法,来
* 计算返回一个数
* child animation delay = child index * delay
*
* index序列从ViewGroup.LayoutParams的AnimationParameters中获取
*/
protected long getDelayForView(View view) {
//获取view的LayoutParams
ViewGroup.LayoutParams lp = view.getLayoutParams();
//在LayoutParams属性中获取view的AnimationParameters
AnimationParameters params = lp.layoutAnimationParameters;
//判断AnimationParameters是否为空
if (params == null) {
return 0;
}
//计算动画的延迟时间delay * duration
final float delay = mDelay * mAnimation.getDuration();
//计算view的延迟时间index * delay
final long viewDelay = (long) (getTransformedIndex(params) * delay);
//view的全部延迟时间delay * count
final float totalDelay = delay * params.count;
//动画的插值器是否为空
if (mInterpolator == null) {
mInterpolator = new LinearInterpolator();
}
float normalizedDelay = viewDelay / totalDelay;
normalizedDelay = mInterpolator.getInterpolation(normalizedDelay);
return (long) (normalizedDelay * totalDelay);
}
- 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
6、获取变换的index顺序
/**
* 变换的index值存储在AnimationParameters对象中
* 子类需要重写这个方法来提供额外的不同顺序。
* 该方法被getDelayForView(android.view.View)调用
*/
protected int getTransformedIndex(AnimationParameters params) {
switch (getOrder()) {
case ORDER_REVERSE:
return params.count - 1 - params.index;
case ORDER_RANDOM:
if (mRandomizer == null) {
mRandomizer = new Random();
}
return (int) (params.count * mRandomizer.nextFloat());
case ORDER_NORMAL:
default:
return params.index;
}
}
针对上面的几个主要方法的源码分析,我们知道如果我们自定义一个LayoutAnimationController,需要我们控制顺序,控制顺序就需要我们重写getTransformedIndex()方法,我们通过AnimationParameters类中的属性进行index的计算。然后由getDelayForView()方法计算每个view的延迟时间。
案例三、GridView动画效果 |
在上一篇博客中,我们了解到GridLayoutAnimationController是一个针对GridView之类具有行列性质控件使用的,所以这篇我们就简要的看看他的效果。既然具有行列性质,那么它的运动方向就比较多。可以同时设置多个方向进行操作。
- public static final int DIRECTION_LEFT_TO_RIGHT = 0x0;从左到右
- public static final int DIRECTION_RIGHT_TO_LEFT = 0x1;从右到左
- public static final int DIRECTION_TOP_TO_BOTTOM = 0x0;从上到下
- public static final int DIRECTION_BOTTOM_TO_TOP = 0x2;从下到上
- public static final int DIRECTION_HORIZONTAL_MASK = 0x1;水平方向
- public static final int DIRECTION_VERTICAL_MASK = 0x2;竖直方向
还有一个问题,就是行列优先级问题。通过函数setDirectionPriority()进行设定。
- public static final int PRIORITY_NONE = 0;行列同级,默认值
- public static final int PRIORITY_COLUMN = 1;列优先
- public static final int PRIORITY_ROW = 2;行优先
动画我们还是采用上面的从下到上的动画,只需要看看使用代码即可。
gridView = (GridView) findViewById(R.id.gridView);
gridView.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_expandable_list_item_1, getData()));
GridLayoutAnimationController gridLayoutAnimationController = new GridLayoutAnimationController(
AnimationUtils.loadAnimation(getApplication(),R.anim.bottom_in));
//设置动画播放顺序
gridLayoutAnimationController.setOrder(LayoutAnimationController.ORDER_NORMAL);
//设置动画播放方向
gridLayoutAnimationController.setDirection(GridLayoutAnimationController.DIRECTION_LEFT_TO_RIGHT);
//设置动画播放顺序的优先级
gridLayoutAnimationController.setDirectionPriority(GridLayoutAnimationController.PRIORITY_NONE);
gridView.setLayoutAnimation(gridLayoutAnimationController);
gridView.startLayoutAnimation();
案例四、自定义LayoutAnimationController |
看下我们的目标效果图:
接着就是我们的自定义LayoutAnimationController。
public class MyLayoutAnimationController extends LayoutAnimationController {
public static final int ORDER_CUSTOM = 6;
public MyLayoutAnimationController(Animation anim) {
super(anim);
}
public MyLayoutAnimationController(Animation anim, float delay) {
super(anim, delay);
}
public MyLayoutAnimationController(Context context, AttributeSet attrs) {
super(context, attrs);
}
protected int getTransformedIndex(AnimationParameters params) {
if(getOrder() == ORDER_CUSTOM){//view顺序以1开头
if(params.index == 2)return 4;
else if(params.index == 3)return 5;
else if(params.index == 4)return 2;
else if(params.index == 5)return 6;
else if(params.index == 6)return 3;
else return params.index;
}else{
return super.getTransformedIndex(params);
}
}
}
eg:
li= (LinearLayout) findViewById(R.id.rl); anim=new AlphaAnimation(0,1); anim.setInterpolator(new LinearInterpolator()); anim.setDuration(200); anim.setFillAfter(true); cont=new LayoutAnimationController(anim); cont.setInterpolator(new LinearInterpolator()); cont.setOrder(LayoutAnimationController.ORDER_RANDOM); but= (Button) findViewById(R.id.but); for(int i=0;i<5;i++){ TextView tv=new TextView(SecondActivity.this); Log.d(TAG, "onClick: i=="+i); tv.setText(i+"==ii"); li.addView(tv); } but.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { li.setLayoutAnimation(cont); li.startLayoutAnimation(); } });