View系列:动画
View Animation(视图动画)
最大的特点是:并没有改变目标实际的属性(宽高/位置等)。例如:移动后,点击原来的位置出发点击事件;移动后再旋转,还是回到原来的位置旋转。
Tween Animation(补间动画)
锚点
可以是数值、百分数、百分数p三种样式,比如50、50%、50%p。[不是只有pivotx/y才可以用这3中样式,其它变换的属性也可以]
- 当为数值时,表示在当前View的左上角,即原点处加上50px,做为起始缩放点;
- 如果是50%,表示在当前控件的左上角加上自己宽度的50%做为起始点;
- 如果是50%p,那么就是表示在当前的左上角加上父控件宽度的50%做为起始点x轴坐标(是在目标的左上角原点加上相对于父控件宽度的距离,不是锚点在父控件的那个位置)。
fromX/toX等等类型的数据也可以用上面的3中数据 类型,只不过有的不适合。比如scale用%p就没意义了。养成好习惯,只在锚点的属性上随便用这3中类型,from/to属性分清类型用相应的数值(浮点倍数/角度...)。
从Animation继承的属性
android:duration 动画持续时间,以毫秒为单位
android:fillAfter 如果设置为true,控件动画结束时,将保持动画最后时的状态
android:fillBefore 如果设置为true,控件动画结束时,还原到开始动画前的状态
android:fillEnabled 与android:fillBefore 效果相同,都是在动画结束时,将控件还原到初始化状态
android:repeatCount 重复次数
android:repeatMode 重复类型,有reverse和restart两个值,reverse表示倒序回放,restart表示重新放一遍,必须与repeatCount一起使用才能看到效果。因为这里的意义是重复的类型,即回放时的动作。
android:interpolator 设定插值器,其实就是指定的动作效果,比如弹跳效果等,不在这小节中讲解,后面会单独列出一单讲解。
scale
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_decelerate_interpolator"
android:duration="700"
android:fromXScale="50%" //也可以用上面的3中类型
android:fromYScale="50%"
android:toXScale="200%"
android:toYScale="200%"
android:pivotX="0.5"
android:pivotY="0.5"
android:repeatCount = "2"
android:repeatMode = "reverse"
android:fillAfter = "true"
/>
alpha
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator"
android:fromAlpha="0.1"
android:toAlpha="1"
android:duration="1500"
android:repeatMode = "reverse"
android:repeatCount = "2"
android:fillAfter = "true"
>
</alpha>
rotate
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator"
android:fromDegrees="0"
android:toDegrees="270"
android:pivotX="50%"
android:pivotY="50%"
android:duration="700"
android:repeatMode = "reverse"
android:repeatCount = "3"
android:fillAfter = "true"
>
</rotate>
translate
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/accelerate_interpolator"
android:duration="700"
android:fillAfter="true"
android:fromXDelta="50"
android:fromYDelta="50%p"
android:repeatCount="3"
android:repeatMode="reverse"
android:toXDelta="70%p"
android:toYDelta="80%p">
</translate>
AnimationSet animSet = new AnimationSet(false);
Animation scaleAnim = AnimationUtils.loadAnimation(this, R.anim.scale_anim); //资源文件
Animation rotateAnim = AnimationUtils.loadAnimation(this, R.anim.rotate_anim);
AlphaAnimation alphaAnim = new AlphaAnimation(0.2f, 1.0f); //代码生成
//valueType 3中类型的数据(px, 自身%, 父类%p),这里已自身为参照物。
TranslateAnimation traslateAnim = new TranslateAnimation(
Animation.RELATIVE_TO_SELF, 0.2f,
Animation.RELATIVE_TO_SELF, 3.0f,
Animation.RELATIVE_TO_SELF, 0f,
Animation.RELATIVE_TO_SELF, 1.0f);
ivTarget.startAnimation(animSet);
自定义Animation
private class MoveAnimation extends Animation {
@Override
protected void applyTransformation(float interpolatedTime, Transformation t) {
super.applyTransformation(interpolatedTime, t);
mInterpolatedTime = interpolatedTime;
invalidate();
}
}
Frame Animation(逐帧动画)
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="true">//false 一直重复执行,true执行一次。
<item
android:duration="200"
android:drawable="@drawable/frame_anim_1"/>
<item
android:duration="200"
android:drawable="@drawable/frame_anim_2"/>
<item
android:duration="200"
android:drawable="@drawable/frame_anim_3"/>
<item
android:duration="200"
android:drawable="@drawable/frame_anim_4"/>
<item
android:duration="200"
android:drawable="@drawable/frame_anim_4"/>
</animation-list>
- 需要注意的是,动画的启动需要在view和window建立连接后才可以绘制,比如上面代码是在用户触摸后启动。如果我们需要打开界面就启动动画的话,则可以在Activity的onWindowFocusChanged()方法中启动。
Property Animation(属性动画)
属性动画是指通过改变View属性来实现动画效果,包括:ValueAnimator、ObjectAnimator、TimeAnimator
ValueAnimator
该类主要针对数值进行改变,不对View进行操作
ValueAnimator animator = ValueAnimator.ofInt(0,400);
animator.setDuration(1000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
//拿到监听结果,自己处理。
int curValue = (int)animation.getAnimatedValue();
tvTextView.layout(curValue,curValue,curValue+tv.getWidth(),curValue+tv.getHeight());
}
});
animator.setInterpolator(new LinearInterpolator());
animator.start();
监听:
/**
* 监听器一:监听动画变化时的实时值
* 添加方法为:public void addUpdateListener(AnimatorUpdateListener listener)
*/
public static interface AnimatorUpdateListener {
void onAnimationUpdate(ValueAnimator animation);
}
/**
* 监听器二:监听动画变化时四个状态
* 添加方法为: public void addListener(AnimatorListener listener)
*/
public static interface AnimatorListener {
void onAnimationStart(Animator animation);
void onAnimationEnd(Animator animation);
void onAnimationCancel(Animator animation);
void onAnimationRepeat(Animator animation);
}
/**
* 移除AnimatorUpdateListener
*/
void removeUpdateListener(AnimatorUpdateListener listener);
void removeAllUpdateListeners();
/**
* 移除AnimatorListener
*/
void removeListener(AnimatorListener listener);
void removeAllListeners();
ObjectAnimator
ValueAnimator只能对数值进行计算,不能直接操作View,需要我们在监听器中自己去操作控件。这样就有点麻烦了,于是Google在ValueAmimator的基础上又派生出了ObjerctAnimator类,让动画直接与控件关联起来。
ObjectAnimator rotateObject = ObjectAnimator.ofFloat(tvPropertyTarget,
"Rotation",
0, 20, -20, 40, -40, 0);
rotateObject.setDuration(2000);
rotateObject.start();
setter/getter 属性名
在View中已经实现了一些属性的setter/getter方法,在构造动画时可以直接对控件使用。
- 要使用一个属性,必须在控件中有对应的setter/getter方法,属性setter/getter方法的命名必须以驼峰方式
- ObjectAnimator在使用该属性的时候,会把setter/getter和属性第一个字母大写转换后的字段拼接成方法名,通过反射的方式调用该方法传值。 所以,上文中"Rotation/rotation"可以首字母可以大小写都行
//1、透明度:alpha
public void setAlpha(float alpha)
//2、旋转度数:rotation、rotationX、rotationY
public void setRotation(float rotation) //围绕Z轴旋转
public void setRotationX(float rotationX)
public void setRotationY(float rotationY)
//3、平移:translationX、translationY
public void setTranslationX(float translationX)
public void setTranslationY(float translationY)
//缩放:scaleX、scaleY
public void setScaleX(float scaleX)
public void setScaleY(float scaleY)
自定义属性做动画
public class PointView extends View {
private float mRadius = 0;
public PointView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onDraw(Canvas canvas) {
}
public void setRadius(float radius){
this.mRadius = radius;
invalidate();
}
public float getRadius(){
return mRadius;
}
}
//radius属性首字母大小写无所谓,最后都是要转成大些的。
ObjectAnimator pointAnim = ObjectAnimator.ofFloat(pointPropertyAnim,
"Radius",
10, 40, 40, 80, 60, 100, 80, 120,60);
pointAnim.start();
什么时候需要用到get方法呢? 前面构造动画时传入的取值范围都是多个参数,Animator知道是从哪个值变化到哪个值。当只传入一个参数的时候,Animator怎么知道哪里是起点?这时通过get方法找到初始值。 如果没有找到get方法,会用该参数类型的默认初始值复制。如:ofInt方法传入一个值,找不到get方法时,默认给的初始值是Int类型的初始值0.
原理
ObjectAnimator的方便之处在于:
ValueAnimator只负责把数值给监听器,ObjectAnimator只负责调用set方法。至于实现,都是靠我们自己或者set中的方法。
插值器
设置动画运行过程中的进度
比例
,类似匀速变化、加速变化、回弹等
- 参数input:是一个float类型,它
取值范围是0到1
,表示当前动画的进度
,取0时表示动画刚开始,取1时表示动画结束,取0.5时表示动画中间的位置,其它类推。 - 返回值:表示当前实际想要显示的进度。取值可以超过1也可以小于0,超过1表示已经超过目标值,小于0表示小于开始位置。(
给估值器使用
) - 插值器默认每10ms刷新一次
public class PointInterpolator implements Interpolator {
/**
* input 是实际动画执行的时间比例 0~1
* newInput 你想让动画已经执行的比例 0~1。
* 注意:都是比例,而不是实际的值。
*
* setDuration(1000)情况下:前200ms走了3/4的路程比例,后800ms走了1/4的路程比例。
*/
@Override
public float getInterpolation(float input) {
if (input <= 0.2) {//后1/4的时间,输出3/4的比例
float newInput = input*4;
return newInput;
}else {//后3/4的时间,输出1/4的比例
float newInput = (float) (input - 0.2)/4 + 0.8f;
return newInput;
}
}
}
使用方式和默认插值器
在xml和代码中使用插值器,省略代码中使用方式
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
// 通过资源ID设置插值器
android:interpolator="@android:anim/overshoot_interpolator"
android:duration="3000"
android:fromXScale="0.0"
android:fromYScale="0.0"
android:pivotX="50%"
android:pivotY="50%"
android:toXScale="2"
android:toYScale="2" />
作用 | 资源ID | 对应的Java类 |
---|---|---|
动画加速进行 | @android:anim/accelerte_interpolator | Acceleraterplator |
快速完成动画,超出再回到到结束样式 | @android:anim/overshoot_interpolator | OvershootInterpolator |
先加速再减速 | @android:anim/accelerate_decelerate_interpolator | AccelerateDecelerateInterpolator |
先退后再加速前进 | @android:anim/anticipate_interpolator | AnticipateInterpolator |
先退后再加速前进,超出终点后再回终点 | @android:anim/anticipate_overshoot_interpolator | AnticipateOvershootInterpolator |
最后阶段弹球效果 | @android:anim/bounce_interpolator | BounceInterpolator |
周期运动 | @android:anim/cycle_interpolator | CycleInterpolator |
减速 | @android:anim/decelerate_interpolator | DecelerateInterpolator |
匀速 | @android:anim/linear_interpolator | LinearInterpolator |
估值器
设置 属性值 从初始值过渡到结束值 的变化
具体数值
- 参数fraction: 表示当前动画的进度(
插值器返回值
) - 返回值:表示当前
对应类型的取值
,也就是UpdateListener接口方法中传入的值
public class PointEvaluator implements TypeEvaluator<Point> {
@Override
public Point evaluate(float fraction, Point startValue, Point endValue) {
int radius = (int) (startValue.getRadius() +
fraction*(endValue.getRadius() - startValue.getRadius()));
return new Point(radius);
}
}
自定义插值器、估值器、属性的使用:
public void doAnimation(){
//ObjectAnimator animator = ObjectAnimator.ofInt(mView, "Radius", 20, 80);
ValueAnimator animatior = new ValueAnimator();
animatior.setObjectValues(new Point(20), new Point(80));
animatior.setInterpolator(new PointInterpolator());
animatior.setEvaluator(new PointEvaluator());
animatior.setDuration(2000);
animatior.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mPoint = (Point) animation.getAnimatedValue();
invalidate();
}
});
animatior.start();
}
PropertyValuesHolder
它其中保存了动画过程中所需要操作的
属性和对应的值
。
通过ObjectAnimator.ofFloat(Object target, String propertyName, float… values)构造的动画,ofFloat()的内部实现其实就是将传进来的参数封装成PropertyValuesHolder实例来保存动画状态,后期的各种操作也是以PropertyValuesHolder为主。
//将需要操作的多个属性和值封装起来,一起放到ObjectAnimator中,相当于set操作。
PropertyValuesHolder rotateHolder = PropertyValuesHolder.ofFloat("Rotation", 0, 360, 0);
PropertyValuesHolder scaleXHolder = PropertyValuesHolder.ofFloat("scaleX", 1, 2, 1,2,1);
PropertyValuesHolder scaleYHolder = PropertyValuesHolder.ofFloat("scaleY", 1, 2, 1,2,1);
ObjectAnimator objectAnim = ObjectAnimator.ofPropertyValuesHolder(ivHolderTarget,
rotateHolder,
scaleXHolder,
scaleYHolder);
objectAnim.setDuration(2000);
objectAnim.setInterpolator(new LinearInterpolator());
objectAnim.start();
KeyFrame(主要帧)
如果想要更精确的控制动画,想要控制整个动画过程的某个点或某个时段达到的值,可以通过自定义插值器或估值器来实现,但是那样又有些费事,并且不容易计算这段时间内值的变化。 这时可以用Keyframe来实现,即设置好某个
时间点和值
,系统会自动计算该点和上个点之间,值的变化。
/***
* 实现左右摇晃,每边最后有震动的效果。
* 摇晃角度100度:0.2f/0.2~0.4/0.4~0.5,分别设置不同的角度和加速器。
* 每个比例点达到哪个角度,这在估值器中也能做到,但是需要自己算每个时间段内值的变化过程。
* KeyFrame可以设置好 比例-值 以后,系统根据默认或设置的加速器改变:上个点和该点内的值如何变换。
* 这样可以更精确的控制动画过程,同时也不用自己费劲去计算值因该如何变换。
*/
Keyframe kfRotation1 = Keyframe.ofFloat(0, 0); //第一帧,如果没有该帧,会直接跳到第二帧开始动画。
//第二帧 0.2f时达到60度,线性加速应该作用于从0~0.2f的这段时间,而不是作用在0.2~0.4f这段。因为已经定好60度是要的结果了,那么实现就应该在前面这段。
Keyframe kfRotation2 = Keyframe.ofFloat(0.2f, 60);
kfRotation2.setInterpolator(new LinearInterpolator());
Keyframe kfRotation3 = Keyframe.ofFloat(0.4f, 100);
kfRotation3.setInterpolator(new BounceInterpolator());
Keyframe kfRotation4 = Keyframe.ofFloat(0.5f, 0);
kfRotation4.setInterpolator(new LinearInterpolator()); //最少有2帧
Keyframe kfRotation5 = Keyframe.ofFloat(0.7f, -60);
kfRotation5.setInterpolator(new LinearInterpolator());
Keyframe kfRotation6 = Keyframe.ofFloat(0.9f, -100);
kfRotation6.setInterpolator(new BounceInterpolator());
Keyframe kfRotation7 = Keyframe.ofFloat(1f, 0);//最后一帧,如果没有该帧,会以最后一个KeyFrame做结尾
kfRotation7.setInterpolator(new LinearInterpolator());
Keyframe kfScaleX1 = Keyframe.ofFloat(0, 1);
Keyframe kfScaleX2 = Keyframe.ofFloat(0.01f,2.8f);
Keyframe kfScaleX3 = Keyframe.ofFloat(0.8f,2.0f);
Keyframe kfScaleX4 = Keyframe.ofFloat(1f,1.0f);
Keyframe kfScaleY1 = Keyframe.ofFloat(0, 1);
Keyframe kfScaleY2 = Keyframe.ofFloat(0.01f,2.8f);
Keyframe kfScaleY4 = Keyframe.ofFloat(0.8f,2.0f);
Keyframe kfScaleY5 = Keyframe.ofFloat(1f,1.0f);
PropertyValuesHolder rotationHolder = PropertyValuesHolder.ofKeyframe("rotation", kfRotation1, kfRotation2, kfRotation3,kfRotation4, kfRotation5, kfRotation6, kfRotation7);
PropertyValuesHolder scaleXHolder = PropertyValuesHolder.ofKeyframe("scaleX", kfScaleX1, kfScaleX2, kfScaleX3, kfScaleX4);
PropertyValuesHolder scaleYHolder = PropertyValuesHolder.ofKeyframe("scaleY", kfScaleY1, kfScaleY2, kfScaleY4, kfScaleY5);
ObjectAnimator objectAnim = ObjectAnimator.ofPropertyValuesHolder(ivHolderTarget,
rotationHolder,
scaleXHolder,
scaleYHolder);
objectAnim.setDuration(1500);
AnimatorSet
AnimatorSet针对ValueAnimator和ObjectAnimator都是适用的,但一般而言,我们不会用到ValueAnimator的组合动画。
playTogether/playSequentially
无论是playTogether还是playSequentially方法,它们只是,仅仅是激活了动画什么时候开始,并不参与动画的具体操作。 例如:如果是playTogether,它只负责这个动画什么时候一起激活,至于anim1/anim2/anim3...哪个马上开始,哪个有延迟,哪个会无限重复,set都不管,只负责一起激活。 如果是playSequentially,它只负责什么时候开始激活第一个(因为有可能set设置延迟),并在第一个动画结束的时候,激活第二个,以此类推。
ObjectAnimator anim1 = ObjectAnimator.ofInt(mTv1, "BackgroundColor", 0xffff00ff, 0xffffff00, 0xffff00ff);
ObjectAnimator anim2 = ObjectAnimator.ofFloat(mTv1, "translationY", 0, 400, 0);
anima2.setStartDelay(2000);
anima2.setRepeatCount(ValueAnimator.INFINITE);
ObjectAnimator anim3 = ObjectAnimator.ofFloat(mTv2, "translationY", 0, 400, 0);
anim3.setStartDelay(2000);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.playTogether(anim1, anim2, anim3);//playSequentially(按次序播放)
animatorSet.setDuration(2000);
animatorSet.setStartDelay(2000);
animatorSet.start();
play(x).with(x)
- play(anim1).with(anim2):2000ms后set开始激活动画,anim1启动,再过2000ms后anim2启动。
- play(anim2).with(anim1):2000ms后set开始激活动画,再过2000ms后启动anim2,并且启动anim1.
set监听
addListener监听的是AnimatorSet的start/end/cacle/repeat。不会监听anim1/anim2的动画状态的。
联合动画XML实现
单独设置和Set中设置
- 以set为准:
//设置单次动画时长
public AnimatorSet setDuration(long duration);
//设置加速器
public void setInterpolator(TimeInterpolator interpolator)
//设置ObjectAnimator动画目标控件
public void setTarget(Object target)
ObjectAnimator anim1 = ObjectAnimator.ofFloat(mTv1, "translationY", 0, 400, 0);
anim1.setDuration(500000000);
ObjectAnimator anim2 = ObjectAnimator.ofFloat(mTv2, "translationY", 0, 400, 0);
anim2.setDuration(3000);//每次3000,而不是3次3000ms
anim2.setRepeatCount(3);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(tv2TranslateY).with(tv1TranslateY);
animatorSet.setDuration(2000);//以Set为准
animatorSet.start();
setDuration()是指单个动画的时间,并不是指总共做完这个动画过程的时间。比如:anim2中设置了3000ms,重复3次。是指每次3000ms,不是3次3000ms。
另外animatorSet设置了时间以后,anim1/anim2虽然也设置了,但是这时以set为准。即,anim1/anim2的单个动画时间为2000ms。只不过anim2是每次2000ms,重复3次,共6000ms。
- 不以set为准:setStartDelay
ObjectAnimator anim1 = ObjectAnimator.ofFloat(mTv1, "translationY", 0, 400, 0);
ObjectAnimator anim2 = ObjectAnimator.ofFloat(mTv2, "translationY", 0, 400, 0);
anim2.setStartDelay(2000);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.addListener(new Animator.AnimatorListener(){...});
animatorSet.play(anim1).with(anim2);
animatorSet.setStartDelay(3000);//指的是Set的激活延迟,而不是动画延迟
animatorSet.setDuration(2000);
animatorSet.start();
setStartDelay不会覆盖单个动画的该方法,只会延长set的激活时间。所以,上面代码中动画的启动过程是:3000ms后set开始激活动画,anim1启动,再过2000ms后anim2启动。
ViewPropertyAnimator
属性动画已不再是针对于View而进行设计的了,而是一种对数值不断操作的过程,我们将属性动画对数值的操作过程设置到指定对象的属性上来,从而形成一种动画的效果。 虽然属性动画给我们提供了ValueAnimator类和ObjectAnimator类,在正常情况下,基本都能满足我们对动画操作的需求,但ValueAnimator类和ObjectAnimator类本身并不是针对View对象的而设计的,而我们在大多数情况下主要都还是对View进行动画操作的。
因此Google官方在Android 3.1系统中补充了ViewPropertyAnimator类,这个类便是专门为View动画而设计的。
- 专门针对View对象动画而操作的类
- 更简洁的链式调用设置多个属性动画,这些动画可以同时进行的
- 拥有更好的性能,多个属性动画是一次同时变化,只执行一次UI刷新(也就是只调用一次invalidate,而n个ObjectAnimator就会进行n次属性变化,就有n次invalidate)
- 每个属性提供两种类型方法设置。scaleX()/scaleXBy()
- 该类只能通过View的animate()获取其实例对象的引用
- 自动调用start
btn.animate()
.alpha(0.5f)
.rotation(360)
.scaleX(1.5f).scaleY(1.5f)
.translationX(50).translationY(50)
.setDuration(5000);
layoutAnimation
布局动画,api1,该属性只对创建ViewGroup时,对其子View有动画。已经创建过了该ViewGroup的话,再向其添加子View不会有动画。
- onCreat创建加载布局时:
//anim -> rotate_anim.xml
<?xml version="1.0" encoding="utf-8"?>
// layoutAnimation标签
<?xml version="1.0" encoding="utf-8"?>
<layoutAnimation
xmlns:android="http://schemas.android.com/apk/res/android"
android:delay="1"
android:animationOrder="normal"
android:animation="@anim/rotate_anim">
</layoutAnimation>
//定义在LinearLayout上,在该界面生成时,Button显示动画。但是,后面在LinearLayout中添加Button时,不再有动画。
<LinearLayout
android:id="@+id/ll_tips_target_animation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layoutAnimation="@anim/layout_animation"
android:tag="在xml中设置的layoutAnimation"
android:orientation="vertical">
<Button
style="@style/base_button"
android:text="ViewGroup初始化时,子View有动画"/>
</LinearLayout>
- 代码中动态设置layoutAnimation,添加View
//代码生成ViewGroup
LinearLayout linear = new LinearLayout(this);
Animation animation = AnimationUtils.loadAnimation(this, R.anim.rotate_anim);
LayoutAnimationController controller = new LayoutAnimationController(animation);
controller.setDelay(1);
//动画模式,正常/倒叙/随机
controller.setOrder(LayoutAnimationController.ORDER_NORMAL);
//设置layoutAnimation
linear.setLayoutAnimation(controller);
linear.setLayoutAnimationListener(new Animation.AnimationListener() {
});
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
linear.setLayoutParams(params);
//给该ViewGroup添加子View,子View会有动画。
addVeiw(linear,null);
llTargetAnim.addView(linear, 0);
使用场景:
该属性只有ViewGroup创建的时候才能有效果,所以不适合动态添加子View的操作显示动画。一般做界面显示的时候的入场动画,比如打开一个界面,多个固定不变的item有动画的显示出来。(进入设置界面,信息展示界面)。
android:animateLayoutChanges属性:
Api11后,添加/移除子View时所带的默认动画,在Xml中设置。不能自定义动画,只能使用默认的。所以,使用范围较小。
<LinearLayout
android:animateLayoutChanges="true"
/>