Defines the layout animation to use the first time the ViewGroup is laid out. Layout animations can also be started manually after the first layout.
layoutAnimation作用的对象是此ViewGroup的直接子view。很好用,比如可以定义ListView条目出现时的动画效果。如下实现的一个简单效果:
layout_anim.xml:
<layoutAnimationxmlns:android="http://schemas.android.com/apk/res/android"
android:animation="@anim/left_in"
android:animationOrder="reverse"
android:delay="0.5"/>
解释:
android:delay=”0.5”: Fraction of the animation duration used to delay the beginning of the animation of each child.意思是一个子view动画执行了50%时,开始执行下一个view动画
android:animationOrder=”reverse”: 子view显示方式,正序、反序、随机
android:animation=”@anim/left_in”: 子view执行的动画
left_in.xml:
<setxmlns:android="http://schemas.android.com/apk/res/android">
<translate
android:duration="2000"
android:fromXDelta="-100%p"
android:interpolator="@android:anim/linear_interpolator"
android:toXDelta="0" />
</set>
布局如下:
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layoutAnimation="@anim/layout_anim"
android:orientation="vertical">
<Button
android:id="@+id/bt_activity_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="activity_layout" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="100dp"
android:background="@color/colorPrimary">
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="2" />
</FrameLayout>
</LinearLayout>
java代码对应实现:
Animation animation = AnimationUtils.loadAnimation(this, R.anim.left_in); LayoutAnimationController lac = new LayoutAnimationController(animation); lac.setOrder(LayoutAnimationController.ORDER_REVERSE); lac.setDelay(0.5f); container.setLayoutAnimation(lac);
LayoutAnimationt效果只有在初次创建时才会有动画,再添加的子View将不再有动画效果,另外类似的还有gridLayoutAnimation
如果想修改动画的一些展现形式,可以继承LayoutAnimationController重写对应方法,如修改对应的子view显示顺序,则可以修改如下方法实现:
protectedintgetTransformedIndex(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;
}
}
当一个ViewGroup中的直接子View 有add/remove/visible/gone/invisible状态变化时,我们想给这些变化一个动画效果,这时就用到了LayoutTransition
系统提供了默认的布局转换动画,只需在ViewGroup的XML布局文件中把添加属性 android:animateLayoutchanges=”true”,默认的效果如下:
自定义变换动画需要用到LayoutTransition类,此类提供了各种属性设置,然后再把此对象传递给ViewGroup,即可。
LayoutTransition四种动画类型:
看下图实现的效果,实现了前3种动画效果:
图片功能表现了view的 add/remove 和 invisible/visible 改变时的动画效果
布局文件activity_layout_transition:
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="@+id/container">
<Button
android:id="@+id/add"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Add button" />
<Button
android:id="@+id/remove"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="remove button" />
<Button
android:id="@+id/change_state"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="First View Visible/Gone" />
</LinearLayout>
Activity主要代码:
@Override
protectedvoidonCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layout_transition);
findViewById(R.id.add).setOnClickListener(this);
findViewById(R.id.remove).setOnClickListener(this);
findViewById(R.id.change_state).setOnClickListener(this);
mContainerView = (LinearLayout) findViewById(R.id.container);
mTransition = new LayoutTransition();
ObjectAnimator animatorAppear = ObjectAnimator.ofFloat(this, "translationX", -600, 0);
ObjectAnimator animatorDissappear = ObjectAnimator.ofFloat(this, "translationX", 0, -600);
// 动画:CHANGE_APPEARING
PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left", 0, 0);
PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top", 0, 0);
PropertyValuesHolder pvhScaleX = PropertyValuesHolder.ofFloat("scaleX", 1f, 0.5f, 1f);
PropertyValuesHolder pvhScaleY = PropertyValuesHolder.ofFloat("scaleY", 1f, 0.5f, 1f);
ObjectAnimator animatorChangeAppear = ObjectAnimator.ofPropertyValuesHolder(this, pvhLeft, pvhTop, pvhScaleX, pvhScaleY);
mTransition.setAnimator(LayoutTransition.APPEARING, animatorAppear);
mTransition.setAnimator(LayoutTransition.DISAPPEARING, animatorDissappear);
mTransition.setInterpolator(LayoutTransition.APPEARING, new AccelerateInterpolator());
mTransition.setInterpolator(LayoutTransition.DISAPPEARING, new LinearInterpolator());
mTransition.setAnimator(LayoutTransition.CHANGE_APPEARING, animatorChangeAppear);
mContainerView.setLayoutTransition(mTransition);
}
@Override
publicvoidonClick(View v){
switch (v.getId()) {
case R.id.add:
addView();
break;
case R.id.remove:
removeView();
break;
case R.id.change_state:
chnageState();
break;
}
}
privatevoidchnageState(){
if (mContainerView.getChildCount() > 3) {
View view = mContainerView.getChildAt(0);
view.setVisibility(view.getVisibility() == View.VISIBLE ? View.INVISIBLE : View.VISIBLE);
}
}
privatevoidaddView(){
mButtonValue++;
Button button = new Button(this);
button.setText("button" + mButtonValue);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(600, ViewGroup.LayoutParams.WRAP_CONTENT);
button.setLayoutParams(params);
mContainerView.addView(button, 0);
}
privatevoidremoveView(){
if (mContainerView.getChildCount() > 3) {
mContainerView.removeViewAt(0);
}
}
CHANGE_APPEARING/CHANGE_DISAPPEARING动画注意事项:
另外还有其它方便的api供调用,这里就不说了。