1.ValueAnimator
1.1 引入属性动画的原因
视图动画虽然能够实现控件的透明度变化、移动、拉伸、旋转,但是无法改变控件的内部属性。看过上篇文章的知道,本质上视图动画就是通过强制父容器重新绘制子View来实现,但是并没有改变子view的内部属性(如颜色,大小,宽高,位置)。例如将TextView从位置A移动到位置C,分别使用视图动画和属性动画。 - 视图动画中,如果给子view设置点击事件,只有在子view的初始位置(A)才会触发点击事件,点击子view的最终位置(C)或者移动轨迹中的位置(B)都不会触发点击事件。属性动画主要针对控件的某个属性做动画。 - 属性动画中,动画开始前,点击位置A触发点击事件,动画开始时,点击运动中的控件即位置B可触发点击事件,动画结束时,点击位置C触发点击事件
1.2 ValueAnimator的简单使用
- 第一步,创建ValueAnimator实例
val animator = ValueAnimator.ofInt(0,400).apply{
duration = 2000
}
animator.start()
在这里我们利用ValueAnimator.ofInt()创建了一个值从0 到 400 变化的动画,动画时长为 2s,从代码中,可以看到,valueAnimator 没有和任何控件相关联,只是进行了值的计算, - 下一步我们需要对valueAnimator的值进行监听,然后自己根据valueAnimator的值来控制控件
animator.addUpdateListener {
val curValue = it.animatedValue.toString()
Log.d("qin", curValue)
//根据valueAnimmator的值来变换textview的位置
tvText.layout(500,curValue.toIntOrNull()?:0,500 + tvText.width,(curValue.toIntOrNull()?:0).plus(tvText.height))
}
打印log如下 注意看打印出来的值不一定连续,有可能重复,有知道原因的好兄弟可以在评论区说一下
1.3 常用函数
- public static ValueAnimator ofInt(int... values) 接收可变长参数,接收的参数越多,变化越多越复杂
-
public static ValueAnimator ofFloat(Float... values) 接收可变长参数,接收的参数越多,变化越多越复杂
-
ValueAnimator setDuration(long duration) 设置动画持续时间
- Object getAnimatedValue() 监听ValueAnimator动画,获取当前的值
- start() 开始动画
- setRepeatCount(int vlaue) 设置循环次数,值为INFININTE(无限循环动画时,在Activity结束时,需要手动调用cancel(),防止内存泄露
- setRepeatMode(int value) 设置循环模式,值为ValueAnimator.REVERSE 或者ValueAnimator.RESTART
- void cancel() 取消动画
- removeUpdateListener(AnimatorUpdateListener listener)移除值变化监听器
- removeAllUptateListeners() 移除所有值变化的监听器
- removeListener(AnimatorListener listener)移除Animator中指定的监听器
- removeAllListeners() 移除所有监听器
- public void setStartDelay(long startDelay) 设置动画延迟多少秒开始
例子如下
val animator = ValueAnimator.ofFloat(0f,100f,30f,300f)
animator.duration = 3000
animator.addUpdateListener{
val curValueFloat = it.animatedValue.toString()
val curValue = curValueFloat.toIntOrNull()
tv.layout(curValue?:0,curValue?:0,(curValue?:0).plus(tv.width),(curValue?:0).plus(tv.heigth))
}
上面代码实现了将textview将从屏幕(0,0)移动到(100,100),再移动到(30,30),最后移动到(300,300)
ValueAnimator有两个不同的监听器,一个addUpdateListener监听值的变化过程,一个AnimatorListener监听动画的某个瞬间
public static interface AnimatorListener{
void onAnimatorStart(Animator animation); //动画开始
void onAnimatorEnd(Animator animation); //动画结束
void onAnimatorCancel(Animator animation); //动画取消
void onAnimatorRepeat(Animator animation); //动画重复
}
开发者可以通过监听ValueAnimator的四个状态start、end、cancel、repeat,来针对动画的不同状态做出特殊处理。
1.4插值器(Interpolator)
1.4.1 AcclerateDecelerateInterpolator(加速减速插值器)
找到它的源码,找出计算方式
@HasNativeInterpolator
public class AccelerateDecelerateInterpolator extends BaseInterpolator
implements NativeInterpolator {
//...省略其他代码
public float getInterpolation(float input) {
return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}
}
可以看出,这时一个余弦函数,使用了这个插值器,刚开始动画的变化速率较慢,然后慢慢加快,最后减慢,然后不断循环,斜率越大的地方,变化越快。
1.4.2 AnticipateInterpolator
AnticipateInterpolator 是初始偏移插值器,表示动画刚开始时向前偏移一段距离,然后应用动画 跟踪源码
public class AnticipateInterpolator extends BaseInterpolator implements NativeInterpolator {
private final float mTension;
public AnticipateInterpolator() {
mTension = 2.0f;
}
//省略其他代码
public float getInterpolation(float t) {
// a(t) = t * t * ((tension + 1) * t - tension)
return t * t * ((mTension + 1) * t - mTension);
}
使用画图工具得出下面图: 因为x 从0开始,刚开始时,向y轴的反方向移动,然后在继续向正方向移动,
1.4.3 BounceInterpolator
弹跳插值器,模拟了控件自由落地后回弹的效果
@HasNativeInterpolator
public class BounceInterpolator extends BaseInterpolator implements NativeInterpolator {
public BounceInterpolator() {
}
@SuppressWarnings({"UnusedDeclaration"})
public BounceInterpolator(Context context, AttributeSet attrs) {
}
private static float bounce(float t) {
return t * t * 8.0f;
}
public float getInterpolation(float t) {
// _b(t) = t * t * 8
// bs(t) = _b(t) for t < 0.3535
// bs(t) = _b(t - 0.54719) + 0.7 for t < 0.7408
// bs(t) = _b(t - 0.8526) + 0.9 for t < 0.9644
// bs(t) = _b(t - 1.0435) + 0.95 for t <= 1.0
// b(t) = bs(t * 1.1226)
t *= 1.1226f;
if (t < 0.3535f) return bounce(t);
else if (t < 0.7408f) return bounce(t - 0.54719f) + 0.7f;
else if (t < 0.9644f) return bounce(t - 0.8526f) + 0.9f;
else return bounce(t - 1.0435f) + 0.95f;
}
效果图如下
![图片描述] 下落时,首先超过了动画的极限1,然后进行第一次回弹,先上移动,速度由快到慢到快,进行第二次回弹,先快到慢,减速
1.4.4 OvershootInterpolator
结束偏移插值器,表示在动画结束时,沿着动画方向继续运动一段距离后结束动画,查看源码
public class OvershootInterpolator extends BaseInterpolator implements NativeInterpolator {
private final float mTension;
public OvershootInterpolator() {
mTension = 2.0f;
}
//..省略代码
mTension = a.getFloat(R.styleable.OvershootInterpolator_tension, 2.0f);
setChangingConfiguration(a.getChangingConfigurations());
a.recycle();
}
public float getInterpolation(float t) {
// _o(t) = t * t * ((tension + 1) * t + tension)
// o(t) = _o(t - 1) + 1
t -= 1.0f;
return t * t * ((mTension + 1) * t + mTension) + 1.0f;
}
}
画出对应的数学图像 在动画快要结束的时候,随着时间的推移,动画进度会超过结束的位置,然后再逐渐返回。
1.4.5 AnticipateOvershootInterpolator
AnticipateOvershootInterpolator 是AniticipateInterpolator 和OvershootInterpolator的结合体,即在动画开始时,先向前偏移一段,动画结束时向后偏移一段。跟踪代码
@HasNativeInterpolator
public class AnticipateOvershootInterpolator extends BaseInterpolator
implements NativeInterpolator {
private final float mTension;
public AnticipateOvershootInterpolator() {
mTension = 2.0f * 1.5f;
}
//省略其他代码
private static float a(float t, float s) {
return t * t * ((s + 1) * t - s);
}
private static float o(float t, float s) {
return t * t * ((s + 1) * t + s);
}
public float getInterpolation(float t) {
// a(t, s) = t * t * ((s + 1) * t - s)
// o(t, s) = t * t * ((s + 1) * t + s)
// f(t) = 0.5 * a(t * 2, tension * extraTension), when t < 0.5
// f(t) = 0.5 * (o(t * 2 - 2, tension * extraTension) + 2), when t <= 1.0
if (t < 0.5f) return 0.5f * a(t * 2.0f, mTension);
else return 0.5f * (o(t * 2.0f - 2.0f, mTension) + 2.0f);
}
}
1.4.6 LinearInterpolator
这个是我们最常见的插值器,表示匀速
@HasNativeInterpolator
public class LinearInterpolator extends BaseInterpolator implements NativeInterpolator {
//...省略其他代码
public float getInterpolation(float input) {
return input;
}
}
1.4.7 AccelerateInterpolator
加速插值器,表示动画开始速率改变的比较慢,然后开始加速 计算方式为:
public class AccelerateInterpolator extends BaseInterpolator implements NativeInterpolator {
private final float mFactor;
private final double mDoubleFactor;
public AccelerateInterpolator() {
mFactor = 1.0f;
mDoubleFactor = 2.0;
}
//省略其他代码
public float getInterpolation(float input) {
if (mFactor == 1.0f) {
return input * input;
} else {
return (float)Math.pow(input, mDoubleFactor);
}
}
}
1.4.8 DecelerateInterpolator
减速插值器,在动画开始时一瞬间加速到最大值,然后逐渐变慢
public class DecelerateInterpolator extends BaseInterpolator implements NativeInterpolator {
public DecelerateInterpolator() {
}
//省略其他代码
public float getInterpolation(float input) {
float result;
if (mFactor == 1.0f) {
result = (float)(1.0f - (1.0f - input) * (1.0f - input));
} else {
result = (float)(1.0f - Math.pow((1.0f - input), 2 * mFactor));
}
return result;
}
## 1.6ValueObject进阶OfObject()
1.4.9 循环插值器
CycleInterpolator是循环插值器,表示动画循环播放特定的次数,速率沿着正弦曲线变化,
public class CycleInterpolator extends BaseInterpolator implements NativeInterpolator {
public float getInterpolation(float input) {
return (float)(Math.sin(2 * mCycles * Math.PI * input));
}
private float mCycles;
}
画出循环2次的函数图像 红色方框代表一次循环
2 ObjectAnimator
2.1 基本使用
上面我们通过ValueAnimator对动画的值进行变化,如果想要改变某个控件的属性,还要监听valueAnimator的动画过程,使用起来比较复杂。ObjectAnimator就是为了解决这个问题,相对于ValueAnimator,ObjectAnimator简化使用的API。ObjectAnimator是ValueAnimator的子类,所有ValueAnimator的方法都可以使用,同时对ofInt()、ofFloat()方法进行了重写,使用方法为:
val animator = ObjectAnimator(tv,"float",1f,0f,1.0f)
animator.duration = 1000
animator.start()
上面代码实现了TextView的透明度从1变到0再变到1, 从上面的代码中可以看到,构造ObjectAnimator的方法非常简单
public static ObjectAnimator ofFloat(object target,string propertyName,float... values)
- 第一个参数用于指定动画要操作的控件
- 第二个参数指定动画要操作的属性
- 第三个参数,可变长参数,上面的代码透明度从1到0再到1
2.2 ObjectAnimaor原理
ObjectAnimator通过构造方法ObjectAnimator()的第2个参数,propertyName,来调用相应的Set()方法,他们定义在View中
//设置透明度
public void setAlpha(float alpha)
//设置绕Z旋转
public void setRotation(float rotation)
//设置绕x轴旋转
public void setRotationX(float rotationX)
//设置绕y轴旋转
public void setRotationY(float rotationY)
//设置移动
public void setTranslateX(float translateX)
public void setTranslateY(float translateY)
//设置缩放
public void setScaleX(float scaleX)
public void setScaleY(float scaleY)
2.3 自定义控件中如何使用ObjectAnimator
首先我们要知道使用ObjectAnimator的前提是,view中有属性名字对应的set(),然后就是set()方法的命名方法是小驼峰,即set后对应的每个单词首字母大写,其余小写
3 AnimatorSet
AnimatorSet可以将ValueAnimator和ObjectAnimator组合到一起,实现组合动画,
3.1 playSequentially()
函数说明如下
public void playSequentially(Animator... items)
public void playSequentially(List<Animator> items)
playSequentially()的意思是先执行完动画一,再执行动画二,动画三
3.2 playTogether
函数说明如下
public void playTogether(Animator... items)
public void playTogether(List<Animator> items)
AnimatorSet中没有设置循环次数的函数,是否无限循环主要看动画本身,和playTogether()、playSequntially()无关
3.3 AnimatorSet.Builder
虽然使用playTogether()和playSquentially()分别能实现动画依次播放和同时开始动画,但是不能非常自由第组合动画,比如我们有3个动画A、B、C,想先播放C,利用上面两个函数没办法实现。
val animatorSet = AnimatorSet()
val buidler = animator.play(tv1)
builder.with(tv1TranslateY)
AnimatorSet.play()这个方法生成Builder()的唯一方法,
//表示要播放某个动画
public Builder play(Animator anim)
//和前面动画一起执行
public Builder with(Animator anim)
//先执行此动画,在执行前面的动画
public Builder before(Animator anim)
//在前面的动画执行完之后,再执行此动画
public Builder after(Animator anim)
//延迟n 毫秒之后执行动画
public Builder after(long delay)
添加监听器,AnimatorSet和ValueAnimator都是同一个父类Animator,所以可以添加下面的监听器
public static interface AnimatorListener{
void onAnimatorStart(Animator animation); //动画开始
void onAnimatorEnd(Animator animation); //动画结束
void onAnimatorCancel(Animator animation); //动画取消
void onAnimatorRepeat(Animator animation); //动画重复
}
4.Evaluator(估值器、计算器)
我们知道创建ValueAnimator实例方法是调用valueAnimator的ofInt(),ofFloat()或者ofObject()静态方法 ofInt()和ofFloat()的计算前面我们都学会了,那么ofObject()呢?初始对象和结束对象,如何过渡?或者说这玩意怎么用? Android原生提供了以下几种Evaluator - IntEvaluator:用于计算int类型属性值的估值器 - FloatEvaluator:用于计算Float类型属性值的估值器 - ArgbEvaluator:用于计算十六进制形式表示颜色值的估值器 - TypeEvaluator:估值器的接口,我们可以实现这个接口来完成自定义估值器 下面我们先来看IntEvaluator内部是怎么是怎么实现的
4.1 IntEvaluator内部实现
public class IntEvaluator implements TypeEvaluator<Integer>{
public Integer evaluate(float frcation,Integer startValue,Integer endValue){
int startInt = startValue;
return (int)(start + fraction*(endValue-startInt);
}
}
- fraction 参数,插值器(Interpolator)中的返回值,以百分制的小数形式表示
- startValue 和 endValue 分别对应ofInt(int start,int end)函数中的start 和 end的数值,比如我们的动画ofInt(100,300)进行到数值进度为20%,那么fraction = 0.2 startvalue = 100,endValue = 300
- 返回值就是当前数值监听器所得到的具体数值,可以通过addUpdateListener监听器进行监听器,然后调用animation.getAnimatedValue()函数得到解决。 计算公式:
返回值 = startValue + (endValue - startValue)* fraction
动画的值 = 初始值 + 完成度 * (结束值 - 初始值)
如果我们想告诉系统如何从初始对象过度到结束对象,那么我们就要自己来实现 TypeEvaluator 接口,即自定义 Evaluator 整个流程为: + ofInt(0,400):定义动画数值区间 + 插值器 : 返回当前动画的进度,比如说 30% + Evaluator :根据插值器返回的动画进度,计算出动画的值,公式为 动画的值 = 初始值 + 完成度 * (结束值 - 初始值) + 然后开发者在监听器addUpdateListener中监听,获取到动画的值
4.2 插值器和Evaluator的区别
插值器只能改变动画速度的快慢,而Evaluator可以通过接收插值器中的动画进度,增加一些自己对动画的处理,改变在addUpdateListener中的值,通过Evaluator 与ofObject的配合,使得valueAnimator更加强大,在Evaluator的处理中,可以给监听器返回一个自定义的对象。
5.PropertyvlauesHolder 和Keyframe
ValueAnimator 和 ObjectAnimator 除了提供ofInt(),ofFloat(),ofObject()方法外,还提供了一个ofPropertyValuesHolder()
public static ValueAnimator ofPropertyValuesHolder(PropertyVlauesHolder... vlaues)
public static ObjbectAnimator ofPropertyValuesHolder(PropertyValuesHolder... values)
ValueAnimator和ObjectAnimator的ofPropertyValuesHolder差不多,这里以ObjectAnimator为例子
5.1概述
PropertyValuesHolder类的含义就是,它其中保存了动画过程所需要操作的属性和对应的值,我们同构ofFloat(Object target,String propertyName,float... values)构建的动画,ofFloat()内部实现其实就是将传入的参数封装成PropertyValuesHolder实例来保存动画状态,后面的各种操作也是以PropertyValusHolder为主。下面是源码
public final class ObjectAnimator extends ValueAnimator {
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
anim.setFloatValues(values);
return anim;
}
}
点击setFloatValue()
//ObjectAnimator.java中
@Override
public void setFloatValues(float... values) {
if (mValues == null || mValues.length == 0) {
// No values yet - this animator is being constructed piecemeal. Init the values with
// whatever the current propertyName is
if (mProperty != null) {
setValues(PropertyValuesHolder.ofFloat(mProperty, values));
} else {
setValues(PropertyValuesHolder.ofFloat(mPropertyName, values));
}
} else {
super.setFloatValues(values);
}
}
//ValueAnimator.java中
public void setValues(PropertyValuesHolder... values) {
int numValues = values.length;
mValues = values;
mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
for (int i = 0; i < numValues; ++i) {
//封装成了PropertyValuesHolder实例
PropertyValuesHolder valuesHolder = values[i];
mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder);
}
// New property/values/target should cause re-initialization prior to starting
mInitialized = false;
}
跟踪到这里我们验证了刚刚结论,动画的状态和参数被封装成了封装成了PropertyValuesHolder实例,并存在以属性名为键的HashMap中
5.2 PropertyValusHolder的常用函数
public static PropertyValuesHolder ofFloat(String propertyName,float... values)
public static PropertyVlauesHolder ofInt(String propertyName,int... values)
public static PropertyValuesHolder ofObject(String propertyName,TypeEvaluator evaluator,object... values)
public static PropertyValuesHolder ofKeyframe(String propertyName,keyframe.. values)
- propertyName 表示ObjectAnimator需要操作的属性名,ObjectAnimator通过反射操作对应的setProperty()
- values 属性所对应的参数,同样是可变长参数,可以指定多个,如果只指定了一个,那么ObjectAnimator会通过查找对应属性getProperty()来获取初始值,
5.3 设置PropertyValuesHolder实例
ObjectAnimator给我们提供了一个设置PropertyValuesHolder实例的入口
public static ObjecetAnimator ofPropertyValuesHolder(Object target ,PropertyValuesHolder... values)
- target 需要执行动画的控件
- values 可变长参数,可以传入多个PropertyValuesHolder实例,由于每个PropertyValuesHolder实例都会针对一个属性执行动画,所以PropertyValuesHolder实例,则会对控件的多个属性同时执行动画操作。
示例如下:
5.4 Keyframe
前面提到,要想动画速率的变化,可以通过自定义插值器,也可以通过自定义Evaluator来实现,但是如果真的让我们从速率变化效果而自定义插值器或者Evaluator大部分要涉及数学知识,恐怕也不容易。 谷歌为根据电影的原理,为我们提供了KeyFrame这一套API,只需要知道动画某个进度点的关键帧,然后API会根据各个帧之间的先后顺序进行平滑过渡。
5.4.1 生成关键帧
public static Keyframe ofFloat(float fraction,float value)
- fraction 当前动画的进度,即插值器中getInterpolation()的返回值
- value:当前动画当前所在的数值的位置
比如Keyframe.ofFloat(0,0)表示动画进度为0时,动画所在数值的位置为0,Keyframe.ofFloat(0.25f,-20f)表示动画进度为25时,动画所在的数值为-20,
5.4.2 关键帧的使用
val frame0 = Keyframe.ofFloat(0f,0)
val frame1 = Keyframe.ofFloat(0.1f,-20f)
val frame2 = keyframe.ofFloat(1f,0)
val frameHolder = PropertyValuesHolder.ofKeyframe("rotation",frame0,frame1,frame2)
val animator = ObjectAnimator.ofPropertyValuesHolder(mImage,frameHolder)
animator.duration = 1000
animator.start()
Keyframe也有一些常用的其他函数用来设置fraction、value、和Interpolator
//设置KeyFrame所对应的进度
public void setFraction(float fraction)
//设置KeyFrame所对应的值
public void setValue(Object value)
//设置插值器
//表示从上一帧到这一帧使用这个插值器
public void setInterpolator(TimeInterpolator interpolator)
实际中使用可以这样
val keyframe3 = Keyframe.ofFloat(1)
keyframe2.value = 0f
//对于keyframe而言,fraction和value这两个参数必须有的,所以不论使用哪种方法实例化Keyframe,都必须保证这两个值被初始化。
//没有使用插值器,系统默认调用线性插值器
5.5 PropertyValuesHolder的其他函数
PropertyValuesHolder除了拥有上面讲到的ofInt(),ofFloat(),ofObject(),ofKeyframe()还有其他函数
//设置动画的Evaluator
public void setEvaluator(TypeEvaluator evaluator)
//设置ofFloat()所对应的动画值列表
public void setFloatValues(float... values)
//用于设置ofInt()所对应的动画值列表
public void setIntValues(int... values)
//用于设置ofkeyframe()所对应的动画值列表
public void setKeyframes(Keyframe... values)
//用于设置ofObject()所对应的动画值列表
public void setObjectValues(Object... values)
//设置动画属性名
public void setPropertyName(String propertyName)
6 为ViewGroup内组件添加动画
前面讲述的ViewAnimator、ObjectAnimator、AnimatorSet都只能针对一个控件做动画,如果我们想对ViewGroup内部控件做统一的入场动画、处场动画,如Recyclerview里面的item的添加、删除、数据更新时的动画,上面3个动都无法做到。 为了解决这个问题,android API 11 开始提供了一个简单的属性android:animateLayoutChanges = "true/false",所有的ViewGroup类控件都有这个属性,只要在xml添加了这个属性,就能实现在添加、删除viewGroup内部控件时的默认动画,但是这个动画不能自定义
6.1 LayoutTransition
上面我们体验了android给我们提供的viewGroup在增加、删除子控件时的默认动画,但是无法使用自定义动画。为了使用自定义动画,我们可以使用LayoutTransition - 创建LayoutTransition示例
-
创建动画并进行设置
-
将LayoutTransition 设置到ViewGroup中
val transitioner = LayoutTransition()
val animOut = ObjectAnimator.ofFloat(null,"rotation",0f,90f,0f)
transitioner.setAnimator(LayoutTransition.DISAPPEARING,animOut)
linearLayout.layoutTransition = transitioner
在第二步中,transitioner.setAnimator设置动画的函数声明如下
public void setAnimator(int transitionType,Animator animator)
其中transitionType表示应用当前动画的对象范围,取值如下: - APPERAING:元素在容器中出现是所定义的动画 - DISAPPEARING :元素在容器中消失时所定义的动画 - CHANGE_APPEARING:由于容器中要显示一个新的元素,其他需要变化的元素所应用的动画 - CHANGE_DISAPPEARING:由于容器中某个元素消失时,其他需要便是的元素所应用的动画
LayoutTransition.CHANGE_APPEARING 和LayoutTransition.CHANGE_DISAPPEARING必须要使用PropertyValuesHolder所构建的动画才会有效果,也就是说使用ObjectAnimator构建的动画,在这里不会有效果。
6.2其他函数
//设置所有动画完成所需要的时间
public void setDuration(long duration)
//针对某个Type设置动画时长
public void setDuration(int transitionType,long duration)
//设置单个Type的插值器
public void setInterpolator(int transitonType,TimeInterpoloator interpolator)
//针对单个type设置动画延时
public void setStartDelay(int transitionType,long delay)
//针对单个Type设置每个子item动画的时间间隔
//参数一:transitionType用于指定Type类型的动画
//参数二:各个item间做动画的间隔
public void setStagger(int transitionType,long duration)
6.3 设置监听
LayoutTransition 提供了一个监听函数
public void addTransitionListener(TransitionListener listener)
//其中TransitionListener
public interfaceTransitionListener{
public void startTransition(LayoutTransition transition,ViewGroup viewGroup,View view,int transitionType)
public void endTransition(LayoutTransition transition,ViewGroup viewGroup,View view,int transitionType)
}
在任何类型的LayoutTransition开始和结束时,都会调用TransitionListener的startTransition() 和 endTransition(),在transitionListener有4个参数
- LayoutTransition transiton 当前的LayoutTransition 实例
- ViewGroup container 当前应用LayoutTransition的容器
- View view 当前正在做动画的View对象
- int transitionType: 当前的LayoutTransition类型取值有: APPEARING,DISAPPEARING,CHANGE_APPEARING和CHANGE_DISAPPEARING
下一篇预告:动画实战实例