Android Animation学习(五) ApiDemos解析:容器布局动画 LayoutTransition

  Property animation系统还提供了对ViewGroup中的View改变加入动画的功能。

  你可以使用LayoutTransition对ViewGroup中的View改变进行动画显示。

  注意,本文所说的动画效果都是设置给容器(ViewGroup),然而效果是通过容器存放的View来体现的。

四种容器转换动画类型

  当你添加或者移除ViewGroup中的View时,或者你调用View的setVisibility()方法来控制其显示或消失时,就处于一个转换状态。这种事件就有可能会激发动画。

  当前被增加或者移除的View可以经历一个出现的动画或者一个消失的动画。

  而且不止是当前要控制的View,ViewGroup中的其他View也可以随之进行变动,比如经历一个动画移动到新的位置。

  所以一共有四种相关的动画类型

  1.View本身的出现动画;

  2.消失动画;

  3.由于新增了其他View而需要改变位置的动画;

  4.由于移除了其他View而需要改变位置的动画。

  (如果增加或移除了其他View之后,当前View的位置不需要改变,则无动画)。

  你可以自定义这些动画,通过setAnimator()方法把它们设置进一个LayoutTransition对象中去。

  设置的时候需要一个Animator对象和一个常数:

  APPEARING - A flag indicating the animation that runs on items that are appearing in the container.

  CHANGE_APPEARING - A flag indicating the animation that runs on items that are changing due to a new item appearing in the container.

  DISAPPEARING - A flag indicating the animation that runs on items that are disappearing from the container.

  CHANGE_DISAPPEARING - A flag indicating the animation that runs on items that are changing due to an item disappearing from the container.

  你可以自己定义这四种事件类型的动画,也可以使用默认的动画。

  最后通过setLayoutTransition(LayoutTransition)方法把这些动画以一个LayoutTransition对象的形式设置给一个ViewGroup即可。

  比如下面这个方法就生成了一个全新的LayoutTransition对象并set给容器(ViewGroup类型),这样四个动画就全是默认动画。

    // 重新生成LayoutTransition对象并设置给container    private void resetTransition() {        mTransitioner = new LayoutTransition();        container.setLayoutTransition(mTransitioner);    }

  为这个mTransitioner对象生成四个自定义动画:

    // 生成自定义动画    private void setupCustomAnimations() {        // 动画:CHANGE_APPEARING        // Changing while Adding        PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left", 0, 1);        PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top", 0, 1);        PropertyValuesHolder pvhRight = PropertyValuesHolder.ofInt("right", 0,                1);        PropertyValuesHolder pvhBottom = PropertyValuesHolder.ofInt("bottom",                0, 1);        PropertyValuesHolder pvhScaleX = PropertyValuesHolder.ofFloat("scaleX",                1f, 0f, 1f);        PropertyValuesHolder pvhScaleY = PropertyValuesHolder.ofFloat("scaleY",                1f, 0f, 1f);        final ObjectAnimator changeIn = ObjectAnimator.ofPropertyValuesHolder(                this, pvhLeft, pvhTop, pvhRight, pvhBottom, pvhScaleX,                pvhScaleY).setDuration(                mTransitioner.getDuration(LayoutTransition.CHANGE_APPEARING));        mTransitioner.setAnimator(LayoutTransition.CHANGE_APPEARING, changeIn);        changeIn.addListener(new AnimatorListenerAdapter() {            public void onAnimationEnd(Animator anim) {                View view = (View) ((ObjectAnimator) anim).getTarget();                view.setScaleX(1f);                view.setScaleY(1f);            }        });        // 动画:CHANGE_DISAPPEARING        // Changing while Removing        Keyframe kf0 = Keyframe.ofFloat(0f, 0f);        Keyframe kf1 = Keyframe.ofFloat(.9999f, 360f);        Keyframe kf2 = Keyframe.ofFloat(1f, 0f);        PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe(                "rotation", kf0, kf1, kf2);        final ObjectAnimator changeOut = ObjectAnimator                .ofPropertyValuesHolder(this, pvhLeft, pvhTop, pvhRight,                        pvhBottom, pvhRotation)                .setDuration(                        mTransitioner                                .getDuration(LayoutTransition.CHANGE_DISAPPEARING));        mTransitioner.setAnimator(LayoutTransition.CHANGE_DISAPPEARING,                changeOut);        changeOut.addListener(new AnimatorListenerAdapter() {            public void onAnimationEnd(Animator anim) {                View view = (View) ((ObjectAnimator) anim).getTarget();                view.setRotation(0f);            }        });        // 动画:APPEARING        // Adding        ObjectAnimator animIn = ObjectAnimator.ofFloat(null, "rotationY", 90f,                0f).setDuration(                mTransitioner.getDuration(LayoutTransition.APPEARING));        mTransitioner.setAnimator(LayoutTransition.APPEARING, animIn);        animIn.addListener(new AnimatorListenerAdapter() {            public void onAnimationEnd(Animator anim) {                View view = (View) ((ObjectAnimator) anim).getTarget();                view.setRotationY(0f);            }        });        // 动画:DISAPPEARING        // Removing        ObjectAnimator animOut = ObjectAnimator.ofFloat(null, "rotationX", 0f,                90f).setDuration(                mTransitioner.getDuration(LayoutTransition.DISAPPEARING));        mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);        animOut.addListener(new AnimatorListenerAdapter() {            public void onAnimationEnd(Animator anim) {                View view = (View) ((ObjectAnimator) anim).getTarget();                view.setRotationX(0f);            }        });    }

默认的布局转换动画

  如果你要使用默认的动画,一个非常简单的方式是在ViewGroup的XML布局文件中把android:animateLayoutchanges属性设置为true。

  这样就自动地按照默认方式来对要移除或添加的View,还有Group中的其他View进行动画。

  比如ApiDemos中的LayoutAnimationsByDefault

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:orientation="vertical" >    <Button        android:id="@+id/addNewButton"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:text="Add Button" />    <!--    <GridLayout        android:columnCount="4"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:id="@+id/gridContainer"        android:animateLayoutChanges="true"        />    -->    <LinearLayout        android:id="@+id/gridContainer"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:animateLayoutChanges="true"         android:orientation="vertical">    </LinearLayout></LinearLayout>

  

  

  我把布局改成了线性布局,只要是ViewGroup类型都可以。

  默认情况下,DISAPPEARING和CHANGE_APPEARING动画是立即开始的,其他动画都有一个默认的开始延迟。

  这是因为,比如:当一个新的View出现的时候,其他View要立即执行CHANGE_APPEARING动画腾出位置,而新出现的View在一定延迟之后再执行APPEARING出现;

  相反地,一个View消失的时候,它需要先DISAPPEARING动画消失,而其他的View需要先等它消失后再执行CHANGE_DISAPPEARING。

  当然这些默认的行为都可以通过setDuration(int, long)setStartDelay(int, long)等方法改变。

API Demos代码

  ApiDemos中布局动画相关的类有:LayoutAnimationsByDefault 、LayoutAnimations、LayoutAnimationsHideShow。

  完整的项目可以去github下载。https://github.com/mengdd/AnimationApiDemos

参考资料

  API Guides: Property Animation

  http://developer.android.com/guide/topics/graphics/prop-animation.html

  其中的Animating Layout Changes to ViewGroups

  LayoutTransition类Reference:

  http://developer.android.com/reference/android/animation/LayoutTransition.html

  项目地址:

  https://github.com/mengdd/AnimationApiDemos

更多相关文章

  1. Android(安卓)SwipeRefreshLayout RecyclerView
  2. Android(安卓)Animation学习(六) View Animation介绍
  3. Android动画效果translate、scale、alpha、rotate的 xml文件写法
  4. Android应用开发中使用GridView网格布局的代码示例
  5. Android(安卓)adapter适配器的使用
  6. Android(安卓)ConstraintLayout 约束布局详解
  7. Android(安卓)开源动画框架 NineOldAndroids
  8. LayoutParams基本使用
  9. Android(安卓)TabLayout 结合ViewPager实现标签页切换

随机推荐

  1. Android(安卓)手机十大必备软件
  2. Android之利用JSBridge库实现Html,JavaScr
  3. Android(安卓)SDK 1.5中文版 (Applicatio
  4. Android开发者必须深入学习的10个应用开
  5. Android入门篇二:使用意图在Activity之间
  6. Android的内存泄漏和调试
  7. 基于MAC Android(安卓)8.1源码下载编译阅
  8. Android100问之什么是Android
  9. QtAndroid详解(5):JNI调用Android系统功能
  10. 自定义实现圆形播放进度条(android,飞一般