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供调用,这里就不说了。