zoukankan      html  css  js  c++  java
  • Android自定义控件:动画类(十三)----animateLayoutChanges与LayoutTransition

    前篇给大家讲了LayoutAnimation的知识,LayoutAnimation虽能实现ViewGroup的进入动画,但只能在创建时有效。在创建后,再往里添加控件就不会再有动画。在API 11后,又添加了两个能实现在创建后添加控件仍能应用动画的方法,分别是android:animateLayoutChanges属性和LayoutTransition类。这篇文章就来简单说一下他们的用法。由于他们的API 等级必须>=11,API等级稍高,且存在较多问题,并不建议读者使用,本篇只讲解具体用法,不做深究.

    一、android:animateLayoutChanges属性

    在API 11之后,Android为了支持ViewGroup类控件,在添加和移除其中控件时自动添加动画,为我们提供了一个非常简单的属性:android:animateLayoutChanges=[true/false],所有派生自ViewGroup的控件都具有此属性,只要在XML中添加上这个属性,就能实现添加/删除其中控件时,带有默认动画了。 
    我们来看下这次的效果图:


    然后来看看具体代码是如何来做的:

    1、main.xml布局代码

    [html] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    3.               android:layout_width="match_parent"  
    4.               android:layout_height="match_parent"  
    5.               android:orientation="vertical">  
    6.   
    7.     <LinearLayout  
    8.             android:layout_width="match_parent"  
    9.             android:layout_height="wrap_content"  
    10.             android:orientation="horizontal">  
    11.   
    12.         <Button  
    13.                 android:id="@+id/add_btn"  
    14.                 android:layout_width="wrap_content"  
    15.                 android:layout_height="wrap_content"  
    16.                 android:text="添加控件"/>  
    17.   
    18.         <Button  
    19.                 android:id="@+id/remove_btn"  
    20.                 android:layout_width="wrap_content"  
    21.                 android:layout_height="wrap_content"  
    22.                 android:text="移除控件"/>  
    23.     </LinearLayout>  
    24.   
    25.   
    26.     <LinearLayout  
    27.             android:id="@+id/layoutTransitionGroup"  
    28.             android:layout_width="match_parent"  
    29.             android:layout_height="wrap_content"  
    30.             android:animateLayoutChanges="true"  
    31.             android:orientation="vertical"/>  
    32.   
    33. </LinearLayout>  
    布局代码很简单,两个按钮,最底部是一个LinearLayout做为动态添加btn的container,注意,我们给它添加了android:animateLayoutChanges="true"也就是说,它内部的控件在添加和删除时,是会带有默认动画。

    2、MyActivity代码

    MyActivity的代码也很简单,就是在点击添加按钮时向其中动态添加一个btn,在点击删除按钮时,将其中第一个按钮给删除。
    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. public class MyActivity extends Activity implements View.OnClickListener {  
    2.     private LinearLayout layoutTransitionGroup;  
    3.   
    4.     private int i = 0;  
    5.     @Override  
    6.     public void onCreate(Bundle savedInstanceState) {  
    7.         super.onCreate(savedInstanceState);  
    8.         setContentView(R.layout.main);  
    9.   
    10.         layoutTransitionGroup = (LinearLayout) findViewById(R.id.layoutTransitionGroup);  
    11.         findViewById(R.id.add_btn).setOnClickListener(this);  
    12.         findViewById(R.id.remove_btn).setOnClickListener(this);  
    13.     }  
    14.   
    15.     private void addButtonView() {  
    16.         i++;  
    17.         Button button = new Button(this);  
    18.         button.setText("button" + i);  
    19.         LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,  
    20.                 ViewGroup.LayoutParams.WRAP_CONTENT);  
    21.         button.setLayoutParams(params);  
    22.         layoutTransitionGroup.addView(button, 0);  
    23.     }  
    24.   
    25.     private void removeButtonView() {  
    26.         if (i > 0) {  
    27.             layoutTransitionGroup.removeViewAt(0);  
    28.         }  
    29.         i--;  
    30.     }  
    31.   
    32.     @Override  
    33.     public void onClick(View v) {  
    34.         if (v.getId() == R.id.add_btn) {  
    35.             addButtonView();  
    36.         }  
    37.         if (v.getId() == R.id.remove_btn) {  
    38.             removeButtonView();  
    39.         }  
    40.   
    41.     }  
    42. }  
    代码很简单就不再细讲了。

    由上面的效果图可见,我们只需要在viewGroup的XML中添加一行代码android:animateLayoutChanges=[true]即可实现内部控件添加删除时都加上动画效果。 
    下面我们来做下对比,如果把上面LinearLayout中的android:animateLayoutChanges=[true]给去掉的效果是怎样的?大家来看下原始添加控件是怎样的,就知道默认动画效果是什么了。 
    在没加android:animateLayoutChanges=true时:


    可见,在添加和删除控件时是没有任何动画的。经过对比就可知道,默认的进入动画就是向下部控件下移,然后新添控件透明度从0到1显示出来。默认的退出动画是控件透明度从1变到0消失,下部控件上移。 

    源码在文章底部给出

    二、LayoutTransaction

    1、概述

    上面虽然在ViewGroup类控件XML中仅添加一行android:animateLayoutChanges=[true]即可实现内部控件添加删除时都加上动画效果。但却只能使用默认动画效果,而无法自定义动画。 
    为了能让我们自定义动画,谷歌在API 11时,同时为我们引入了一个类LayoutTransaction。 
    要使用LayoutTransaction是非常容易的,只需要三步: 

    第一步:创建实例

    [html] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. LayoutTransaction transitioner = new LayoutTransition();  
    第二步:创建动画并设置

    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. ObjectAnimator animOut = ObjectAnimator.ofFloat(null"rotation", 0f, 90f, 0f);  
    2. transitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);  
    第三步:将LayoutTransaction设置进ViewGroup
    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. linearLayout.setLayoutTransition(mTransitioner);  
    其中第三步中,在API 11之后,所有派生自ViewGroup类,比如LinearLayout,FrameLayout,RelativeLayout等,都具有一个专门用来设置LayoutTransition的方法:
    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. public void setLayoutTransition(LayoutTransition transition)  
    在第二步中,transitioner.setAnimator设置动画的函数声明为:
    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. public void setAnimator(int transitionType, Animator animator)  
    其中 
    第一个参数int transitionType:表示当前应用动画的对象范围,取值有:
    • APPEARING —— 元素在容器中出现时所定义的动画。
    • DISAPPEARING —— 元素在容器中消失时所定义的动画。
    • CHANGE_APPEARING —— 由于容器中要显现一个新的元素,其它需要变化的元素所应用的动画
    • CHANGE_DISAPPEARING —— 当容器中某个元素消失,其它需要变化的元素所应用的动画 
    这几个具体的意义,我们后面会具体来讲。
    第二个参数Animator animator:表示当前所选范围的控件所使用的动画。

    2、LayoutTransition.APPEARING与LayoutTransition.DISAPPEARING示例

    我们先来看看LayoutTransition.APPEARING与LayoutTransition.DISAPPEARING分别代表什么意义: 
    我们先来看效果图:

    大家可以看到,在新增一个btn时,这个新增的btn会有一个绕Y轴旋转360度的动画。这个就是LayoutTransition.APPEARING所对应的当一个控件出现时所对应的动画。 
    当我们从容器中移除一个控件时,这个被移除的控件会绕Z轴旋转90度后,再消失。这个就是LayoutTransition.DISAPPEARING在一个控件被移除时,此被移除的控件所对应的动画。 
    这样大家就理解了,LayoutTransition.APPEARING和LayoutTransition.DISAPPEARING的意义。下面我们就来看看代码吧。 
    这个示例也是建立在上个android:animateLayoutChanges属性所对应示例的基础上的,所以框架部分是一样的,仅列出代码,不再多讲,只讲关键部分 
    首先是main.xml布局

    [html] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. <?xml version="1.0" encoding="utf-8"?>  
    2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
    3.               android:layout_width="match_parent"  
    4.               android:layout_height="match_parent"  
    5.               android:orientation="vertical">  
    6.   
    7.     <LinearLayout  
    8.             android:layout_width="match_parent"  
    9.             android:layout_height="wrap_content"  
    10.             android:orientation="horizontal">  
    11.   
    12.         <Button  
    13.                 android:id="@+id/add_btn"  
    14.                 android:layout_width="wrap_content"  
    15.                 android:layout_height="wrap_content"  
    16.                 android:text="添加控件"/>  
    17.   
    18.         <Button  
    19.                 android:id="@+id/remove_btn"  
    20.                 android:layout_width="wrap_content"  
    21.                 android:layout_height="wrap_content"  
    22.                 android:text="移除控件"/>  
    23.     </LinearLayout>  
    24.   
    25.   
    26.     <LinearLayout  
    27.             android:id="@+id/layoutTransitionGroup"  
    28.             android:layout_width="match_parent"  
    29.             android:layout_height="wrap_content"  
    30.             android:orientation="vertical"/>  
    31.   
    32. </LinearLayout>  
    布局代码与上面一样,但唯一不同的是在LinearLayout中没有android:animateLayoutChanges="true" 
    然后是在MyActivity中的代码处理
    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. public class MyActivity extends Activity implements View.OnClickListener{  
    2.     private LinearLayout layoutTransitionGroup;  
    3.     private LayoutTransition mTransitioner;  
    4.     private int i = 0;  
    5.   
    6.     @Override  
    7.     public void onCreate(Bundle savedInstanceState) {  
    8.         super.onCreate(savedInstanceState);  
    9.         setContentView(R.layout.main);  
    10.   
    11.         layoutTransitionGroup = (LinearLayout) findViewById(R.id.layoutTransitionGroup);  
    12.         findViewById(R.id.add_btn).setOnClickListener(this);  
    13.         findViewById(R.id.remove_btn).setOnClickListener(this);  
    14.   
    15.         mTransitioner = new LayoutTransition();  
    16.         //入场动画:view在这个容器中消失时触发的动画  
    17.         ObjectAnimator animIn = ObjectAnimator.ofFloat(null"rotationY", 0f, 360f,0f);  
    18.         mTransitioner.setAnimator(LayoutTransition.APPEARING, animIn);  
    19.   
    20.         //出场动画:view显示时的动画  
    21.         ObjectAnimator animOut = ObjectAnimator.ofFloat(null"rotation", 0f, 90f, 0f);  
    22.         mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);  
    23.   
    24.         layoutTransitionGroup.setLayoutTransition(mTransitioner);  
    25.     }  
    26.   
    27.   
    28.     private void addButtonView() {  
    29.         i++;  
    30.         Button button = new Button(this);  
    31.         button.setText("button" + i);  
    32.         LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,  
    33.                 ViewGroup.LayoutParams.WRAP_CONTENT);  
    34.         button.setLayoutParams(params);  
    35.         layoutTransitionGroup.addView(button, 0);  
    36.     }  
    37.   
    38.     private void removeButtonView() {  
    39.         if (i > 0) {  
    40.             layoutTransitionGroup.removeViewAt(0);  
    41.         }  
    42.         i--;  
    43.     }  
    44.   
    45.     @Override  
    46.     public void onClick(View v) {  
    47.         if (v.getId() == R.id.add_btn) {  
    48.             addButtonView();  
    49.         }  
    50.         if (v.getId() == R.id.remove_btn) {  
    51.             removeButtonView();  
    52.         }  
    53.   
    54.     }  
    55. }  
    同样是在点击“添加控件”按钮时,向LinearLayout中动态添加一个控件,在点击“移除控件”按钮时,将LinearLayout中第一个控件给移除。
    但是非常注意的是我们的LayoutTransition是在OnCreate中设置的,也就是说是在LinearLayout创建时就给它定义好控件的入场动画和出场动画的,定义代码如下:
    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. mTransitioner = new LayoutTransition();  
    2. //入场动画:view在这个容器中消失时触发的动画  
    3. ObjectAnimator animIn = ObjectAnimator.ofFloat(null"rotationY", 0f, 360f,0f);  
    4. mTransitioner.setAnimator(LayoutTransition.APPEARING, animIn);  
    5.   
    6. //出场动画:view显示时的动画  
    7. ObjectAnimator animOut = ObjectAnimator.ofFloat(null"rotation", 0f, 90f, 0f);  
    8. mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);  
    9.   
    10. layoutTransitionGroup.setLayoutTransition(mTransitioner);  
    代码难度不大,也就是我们这节开始时所讲的那三步: 
    第一步,定义LayoutTransition实例:
    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. mTransitioner = new LayoutTransition();  
    第二步:创建动画并设置
    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. //入场动画:view在这个容器中消失时触发的动画  
    2. ObjectAnimator animIn = ObjectAnimator.ofFloat(null"rotationY", 0f, 360f,0f);  
    3. mTransitioner.setAnimator(LayoutTransition.APPEARING, animIn);  
    4.   
    5. //出场动画:view显示时的动画  
    6. ObjectAnimator animOut = ObjectAnimator.ofFloat(null"rotation", 0f, 90f, 0f);  
    7. mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);  
    分别定义了,当一个控件被插入时,这个被插入的控件所使用的动画:即绕Y轴旋转360度。
    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. ObjectAnimator animIn = ObjectAnimator.ofFloat(null"rotationY", 0f, 360f,0f);  
    2. mTransitioner.setAnimator(LayoutTransition.APPEARING, animIn);  
    然后是当一个控件被移除时,这个被移除的控件所使用的动画:即绕Z轴旋转90度:
    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. ObjectAnimator animOut = ObjectAnimator.ofFloat(null"rotation", 0f, 90f, 0f);  
    2. mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);  
    第三步:将LayoutTransaction设置进ViewGroup
    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. layoutTransitionGroup.setLayoutTransition(mTransitioner);  
    这段代码很容易理解,没什么难度,这里涉及到ObjectAnimator相关的动画知识,如果有不理解的同学请参考《Animation动画详解(七)——ObjectAnimator基本使用》

    3、LayoutTransition.CHANGE_APPEARING与LayoutTransition.CHANGE_DISAPPEARING

    我们先来看下本例的效果图,先理解LayoutTransition.CHANGE_APPEARING和LayoutTransition.CHANGE_DISAPPEARING分别是什么意义

    在这个效果图中,在添加控件时,除了被添加控件本身的入场动画以外,其它需要移动位置的控件,在移动位置时,也被添加上了动画(left点位移动画),这些除了被添加控件以外的其它需要移动位置的控件组合,所对应的动画就是LayoutTransition.CHANGE_APPEARING 
    同样,在移除一个控件时,因为移除了一个控件,而其它所有需要改变位置的控件组合所对应的动画就是LayoutTransition.CHANGE_DISAPPEARING,这里LayoutTransition.CHANGE_DISAPPEARING所对应的动画是 
    《 Animation动画详解(八)——PropertyValuesHolder与Keyframe》的响铃效果。 

    (1)、LayoutTransition.CHANGE_APPEARING实现

    我们这里先看看LayoutTransition.CHANGE_APPEARING所对应的完整代码
    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. public void onCreate(Bundle savedInstanceState) {  
    2.     super.onCreate(savedInstanceState);  
    3.     setContentView(R.layout.main);  
    4.   
    5.     layoutTransitionGroup = (LinearLayout) findViewById(R.id.layoutTransitionGroup);  
    6.     findViewById(R.id.add_btn).setOnClickListener(this);  
    7.     findViewById(R.id.remove_btn).setOnClickListener(this);  
    8.   
    9.     mTransitioner = new LayoutTransition();  
    10.     //入场动画:view在这个容器中消失时触发的动画  
    11.     ObjectAnimator animIn = ObjectAnimator.ofFloat(null"rotationY", 0f, 360f,0f);  
    12.     mTransitioner.setAnimator(LayoutTransition.APPEARING, animIn);  
    13.   
    14.     //出场动画:view显示时的动画  
    15.     ObjectAnimator animOut = ObjectAnimator.ofFloat(null"rotation", 0f, 90f, 0f);  
    16.     mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);  
    17.   
    18.     PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,100,0);  
    19.     PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",1,1);  
    20.     Animator changeAppearAnimator  
    21.             = ObjectAnimator.ofPropertyValuesHolder(layoutTransitionGroup, pvhLeft,pvhBottom,pvhTop,pvhRight);  
    22.     mTransitioner.setAnimator(LayoutTransition.CHANGE_APPEARING,changeAppearAnimator);  
    23.   
    24.     layoutTransitionGroup.setLayoutTransition(mTransitioner);  
    25. }  
    入场动画((LayoutTransition.APPEARING)和出场动画(LayoutTransition.DISAPPEARING)我们已经讲过了,下面我们主要看看入场时,其它控件位移动画的部分:
    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,100,0);  
    2. PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",1,1);  
    3. Animator changeAppearAnimator  
    4.         = ObjectAnimator.ofPropertyValuesHolder(layoutTransitionGroup, pvhLeft,pvhBottom,pvhTop,pvhRight);  
    5. mTransitioner.setAnimator(LayoutTransition.CHANGE_APPEARING,changeAppearAnimator);  
    这里有几点注意事项: 
    1、LayoutTransition.CHANGE_APPEARING和LayoutTransition.CHANGE_DISAPPEARING必须使用PropertyValuesHolder所构造的动画才会有效果,不然无效!也就是说使用ObjectAnimator构造的动画,在这里是不会有效果的! 
    2、在构造PropertyValuesHolder动画时,”left”、”top”属性的变动是必写的。如果不需要变动,则直接写为:
    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,0);  
    2. PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",0,0);  
    3、在构造PropertyValuesHolder时,所使用的ofInt,ofFloat中的参数值,第一个值和最后一个值必须相同,不然此属性所对应的的动画将被放弃,在此属性值上将不会有效果;
    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,100,0);  
    比如,这里ofInt(“left”,0,100,0)第一个值和最后一个值都是0,所以这里会有效果的,如果我们改为ofInt(“left”,0,100);那么由于首尾值不一致,则将被视为无效参数,将不会有效果! 
    4、在构造PropertyValuesHolder时,所使用的ofInt,ofFloat中,如果所有参数值都相同,也将不会有动画效果。 
    比如:
    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",100,100);  
    在这条语句中,虽然首尾一致,但由于全程参数值相同,所以left属性上的这个动画会被放弃,在left属性上也不会应用上任何动画。 
    看到了吧,坑就是如此多,至于这些都是为什么,我也懒得去研究它的源码,因为LayoutTransition的问题实在是太!多!了!至于这篇文章嘛,由于这是一个Android 动画的系列,而LayoutTransition也是其中一员,本着尊重知识的原则,还是给大家讲一讲,至于应用嘛!呵呵,慎用之…… 
    我们上面讲了,left,top属性是必须的,下面我们给他扩展一下,除了给它添加left,top属性以外,再给它加上scale属性,让它同时放大,代码即:
    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,100,0);  
    2. PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",1,1);  
    3. PropertyValuesHolder pvhScaleX = PropertyValuesHolder.ofFloat("ScaleX",1f,9f,1f);  
    4. Animator changeAppearAnimator  
    5.        = ObjectAnimator.ofPropertyValuesHolder(layoutTransitionGroup, pvhLeft,pvhTop,pvhScaleX);  
    6. mTransitioner.setAnimator(LayoutTransition.CHANGE_APPEARING,changeAppearAnimator);  
    对应动画效果为:

    (2)、LayoutTransition.CHANGE_DISAPPEARING实现

    好了,我们下面来看看LayoutTransition.CHANGE_DISAPPEARING的具体实现

    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. PropertyValuesHolder outLeft = PropertyValuesHolder.ofInt("left",0,0);  
    2. PropertyValuesHolder outTop = PropertyValuesHolder.ofInt("top",0,0);  
    3.   
    4. Keyframe frame0 = Keyframe.ofFloat(0f, 0);  
    5. Keyframe frame1 = Keyframe.ofFloat(0.1f, -20f);  
    6. Keyframe frame2 = Keyframe.ofFloat(0.2f, 20f);  
    7. Keyframe frame3 = Keyframe.ofFloat(0.3f, -20f);  
    8. Keyframe frame4 = Keyframe.ofFloat(0.4f, 20f);  
    9. Keyframe frame5 = Keyframe.ofFloat(0.5f, -20f);  
    10. Keyframe frame6 = Keyframe.ofFloat(0.6f, 20f);  
    11. Keyframe frame7 = Keyframe.ofFloat(0.7f, -20f);  
    12. Keyframe frame8 = Keyframe.ofFloat(0.8f, 20f);  
    13. Keyframe frame9 = Keyframe.ofFloat(0.9f, -20f);  
    14. Keyframe frame10 = Keyframe.ofFloat(10);  
    15. PropertyValuesHolder mPropertyValuesHolder = PropertyValuesHolder.ofKeyframe("rotation",frame0,frame1,frame2,frame3,frame4,frame5,frame6,frame7,frame8,frame9,frame10);  
    16.   
    17. ObjectAnimator mObjectAnimatorChangeDisAppearing = ObjectAnimator.ofPropertyValuesHolder(this, outLeft,outTop,mPropertyValuesHolder);  
    18. mTransitioner.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, mObjectAnimatorChangeDisAppearing);  
    第一步:由于left,top属性是必须的,但我们做响铃效果时,是不需要Left,top变动的,所有给他们设置为无效值:(看到了没,必须设置的意思就是即使设置的值是无效的,也要设置!不然就会由于Left,top属性没有设置而整个PropertyValuesHolder动画无效,好恶心的用法……大家可以在源码注掉哪句话,或者把上面的所有无效设置尝试一遍,看看效果便知)
    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. PropertyValuesHolder outLeft = PropertyValuesHolder.ofInt("left",0,0);  
    2. PropertyValuesHolder outTop = PropertyValuesHolder.ofInt("top",0,0);  
    第二步:用KeyFrame构造PropertyValuesHolder
    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. Keyframe frame0 = Keyframe.ofFloat(0f, 0);  
    2. Keyframe frame1 = Keyframe.ofFloat(0.1f, -20f);  
    3. Keyframe frame2 = Keyframe.ofFloat(0.2f, 20f);  
    4. Keyframe frame3 = Keyframe.ofFloat(0.3f, -20f);  
    5. Keyframe frame4 = Keyframe.ofFloat(0.4f, 20f);  
    6. Keyframe frame5 = Keyframe.ofFloat(0.5f, -20f);  
    7. Keyframe frame6 = Keyframe.ofFloat(0.6f, 20f);  
    8. Keyframe frame7 = Keyframe.ofFloat(0.7f, -20f);  
    9. Keyframe frame8 = Keyframe.ofFloat(0.8f, 20f);  
    10. Keyframe frame9 = Keyframe.ofFloat(0.9f, -20f);  
    11. Keyframe frame10 = Keyframe.ofFloat(10);  
    12. PropertyValuesHolder mPropertyValuesHolder = PropertyValuesHolder.ofKeyframe("rotation",frame0,frame1,frame2,frame3,frame4,frame5,frame6,frame7,frame8,frame9,frame10);  
    PropertyValuesHolder的构造方法总共有四个:ofInt,ofFloat,ofObject,ofKeyFrame,这些方法的具体用法已经在《Animation动画详解(八)——PropertyValuesHolder与Keyframe》中已经详细讲解,这里就不再赘述,有关响铃效果也是从这篇文章中摘出,所以这里也不再讲解。 
    最后一步,设置LayoutTransition.CHANGE_DISAPPEARING动画
    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. ObjectAnimator mObjectAnimatorChangeDisAppearing = ObjectAnimator.ofPropertyValuesHolder(this, outLeft,outTop,mPropertyValuesHolder);  
    2. mTransitioner.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, mObjectAnimatorChangeDisAppearing);  

    对应效果为:


    所以所有动画所对应的完整代码如下:

    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. public void onCreate(Bundle savedInstanceState) {  
    2.    super.onCreate(savedInstanceState);  
    3.    setContentView(R.layout.main);  
    4.   
    5.    layoutTransitionGroup = (LinearLayout) findViewById(R.id.layoutTransitionGroup);  
    6.    findViewById(R.id.add_btn).setOnClickListener(this);  
    7.    findViewById(R.id.remove_btn).setOnClickListener(this);  
    8.   
    9.    mTransitioner = new LayoutTransition();  
    10.    //入场动画:view在这个容器中消失时触发的动画  
    11.    ObjectAnimator animIn = ObjectAnimator.ofFloat(null"rotationY", 0f, 360f,0f);  
    12.    mTransitioner.setAnimator(LayoutTransition.APPEARING, animIn);  
    13.   
    14.    //出场动画:view显示时的动画  
    15.    ObjectAnimator animOut = ObjectAnimator.ofFloat(null"rotation", 0f, 90f, 0f);  
    16.    mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);  
    17.   
    18.    /** 
    19.     * LayoutTransition.CHANGE_APPEARING动画 
    20.     */  
    21.    PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,100,0);  
    22.    PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",1,1);  
    23.    //必须第一个值与最后一值相同才会有效果,不然没有效果  
    24.    PropertyValuesHolder pvhScaleX = PropertyValuesHolder.ofFloat("ScaleX",1f,9f,1f);  
    25.    Animator changeAppearAnimator  
    26.            = ObjectAnimator.ofPropertyValuesHolder(layoutTransitionGroup, pvhLeft,pvhTop,pvhScaleX);  
    27.    mTransitioner.setAnimator(LayoutTransition.CHANGE_APPEARING,changeAppearAnimator);  
    28.   
    29.    /** 
    30.     * LayoutTransition.CHANGE_DISAPPEARING动画 
    31.     */  
    32.    PropertyValuesHolder outLeft = PropertyValuesHolder.ofInt("left",0,0);  
    33.    PropertyValuesHolder outTop = PropertyValuesHolder.ofInt("top",0,0);  
    34.   
    35.    Keyframe frame0 = Keyframe.ofFloat(0f, 0);  
    36.    Keyframe frame1 = Keyframe.ofFloat(0.1f, -20f);  
    37.    Keyframe frame2 = Keyframe.ofFloat(0.2f, 20f);  
    38.    Keyframe frame3 = Keyframe.ofFloat(0.3f, -20f);  
    39.    Keyframe frame4 = Keyframe.ofFloat(0.4f, 20f);  
    40.    Keyframe frame5 = Keyframe.ofFloat(0.5f, -20f);  
    41.    Keyframe frame6 = Keyframe.ofFloat(0.6f, 20f);  
    42.    Keyframe frame7 = Keyframe.ofFloat(0.7f, -20f);  
    43.    Keyframe frame8 = Keyframe.ofFloat(0.8f, 20f);  
    44.    Keyframe frame9 = Keyframe.ofFloat(0.9f, -20f);  
    45.    Keyframe frame10 = Keyframe.ofFloat(10);  
    46.    PropertyValuesHolder mPropertyValuesHolder = PropertyValuesHolder.ofKeyframe("rotation",frame0,frame1,frame2,frame3,frame4,frame5,frame6,frame7,frame8,frame9,frame10);  
    47.   
    48.    ObjectAnimator mObjectAnimatorChangeDisAppearing = ObjectAnimator.ofPropertyValuesHolder(this, outLeft,outTop,mPropertyValuesHolder);  
    49.    mTransitioner.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, mObjectAnimatorChangeDisAppearing);  
    50.   
    51.    layoutTransitionGroup.setLayoutTransition(mTransitioner);  
    52. }     
    源码在文章底部给出

    4、其它函数

    (1)、基本设置

    上面我们讲了LayoutTransition的setAnimator方法,在LayoutTransition中还有一些其它方法,下面我们来讲解下:
    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. /** 
    2.  * 设置所有动画完成所需要的时长 
    3.  */  
    4. public void setDuration(long duration)  
    5. /** 
    6.  * 针对单个type,设置动画时长; 
    7.  * transitionType取值为:APPEARING、DISAPPEARING、CHANGE_APPEARING、CHANGE_DISAPPEARING 
    8.  */  
    9. public void setDuration(int transitionType, long duration)   
    10. /** 
    11.  * 针对单个type设置插值器 
    12.  * transitionType取值为:APPEARING、DISAPPEARING、CHANGE_APPEARING、CHANGE_DISAPPEARING 
    13.  */  
    14. public void setInterpolator(int transitionType, TimeInterpolator interpolator)  
    15. /** 
    16.  * 针对单个type设置动画延时 
    17.  * transitionType取值为:APPEARING、DISAPPEARING、CHANGE_APPEARING、CHANGE_DISAPPEARING 
    18.  */  
    19. public void setStartDelay(int transitionType, long delay)  
    20. /** 
    21.  * 针对单个type设置,每个子item动画的时间间隔 
    22.  */  
    23. public void setStagger(int transitionType, long duration)  
    除了setStagger以外,如果你把我的Animation系列一路看下来的话,其它这些函数理解起来只能说so easy,这里就不再举例了,下面我们讲讲setStagger用法与效果 
    我们还回来看看上面的效果图:

    在这个效果图中,当插入一个控件时,CHANGE_APPEARING动画时的所有控件是一起做动画的,我们需要做动画的控件,逐个做动画,而不是一起全部来做动画,setStagger就是用来设置单个item间的动画间隔的。 
    在上面的基础上,我们给LayoutTransition.CHANGE_APPEARING添加上每个item间的时间间隔30ms:

    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. mTransitioner.setStagger(LayoutTransition.CHANGE_APPEARING, 30);  
    动画效果为:

    明显可以看出,做LayoutTransition.CHANGE_APPEARING的控件确实是有间隔的; 
    完整代码为:

    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. public void onCreate(Bundle savedInstanceState) {  
    2.     super.onCreate(savedInstanceState);  
    3.     setContentView(R.layout.main);  
    4.   
    5.     layoutTransitionGroup = (LinearLayout) findViewById(R.id.layoutTransitionGroup);  
    6.     findViewById(R.id.add_btn).setOnClickListener(this);  
    7.     findViewById(R.id.remove_btn).setOnClickListener(this);  
    8.   
    9.     mTransitioner = new LayoutTransition();  
    10.     //入场动画:view在这个容器中消失时触发的动画  
    11.     ObjectAnimator animIn = ObjectAnimator.ofFloat(null"rotationY", 0f, 360f,0f);  
    12.     mTransitioner.setAnimator(LayoutTransition.APPEARING, animIn);  
    13.   
    14.     //出场动画:view显示时的动画  
    15.     ObjectAnimator animOut = ObjectAnimator.ofFloat(null"rotation", 0f, 90f, 0f);  
    16.     mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);  
    17.   
    18.   
    19.     /** 
    20.      * LayoutTransition.CHANGE_APPEARING动画 
    21.      */  
    22.     PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,100,0);  
    23.     PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",1,1);  
    24.     //必须第一个值与最后一值相同才会有效果,不然没有效果  
    25.     PropertyValuesHolder pvhScaleX = PropertyValuesHolder.ofFloat("ScaleX",1f,9f,1f);  
    26.     Animator changeAppearAnimator  
    27.             = ObjectAnimator.ofPropertyValuesHolder(layoutTransitionGroup, pvhLeft,pvhTop,pvhScaleX);  
    28.     mTransitioner.setAnimator(LayoutTransition.CHANGE_APPEARING,changeAppearAnimator);  
    29.   
    30.   
    31.     /** 
    32.      * LayoutTransition.CHANGE_DISAPPEARING动画 
    33.      */  
    34.     PropertyValuesHolder outLeft = PropertyValuesHolder.ofInt("left",0,0);  
    35.     PropertyValuesHolder outTop = PropertyValuesHolder.ofInt("top",0,0);  
    36.   
    37.     Keyframe frame0 = Keyframe.ofFloat(0f, 0);  
    38.     Keyframe frame1 = Keyframe.ofFloat(0.1f, -20f);  
    39.     Keyframe frame2 = Keyframe.ofFloat(0.2f, 20f);  
    40.     Keyframe frame3 = Keyframe.ofFloat(0.3f, -20f);  
    41.     Keyframe frame4 = Keyframe.ofFloat(0.4f, 20f);  
    42.     Keyframe frame5 = Keyframe.ofFloat(0.5f, -20f);  
    43.     Keyframe frame6 = Keyframe.ofFloat(0.6f, 20f);  
    44.     Keyframe frame7 = Keyframe.ofFloat(0.7f, -20f);  
    45.     Keyframe frame8 = Keyframe.ofFloat(0.8f, 20f);  
    46.     Keyframe frame9 = Keyframe.ofFloat(0.9f, -20f);  
    47.     Keyframe frame10 = Keyframe.ofFloat(10);  
    48.     PropertyValuesHolder mPropertyValuesHolder = PropertyValuesHolder.ofKeyframe("rotation",frame0,frame1,frame2,frame3,frame4,frame5,frame6,frame7,frame8,frame9,frame10);  
    49.   
    50.     ObjectAnimator mObjectAnimatorChangeDisAppearing = ObjectAnimator.ofPropertyValuesHolder(this, outLeft,outTop,mPropertyValuesHolder);  
    51.     mTransitioner.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, mObjectAnimatorChangeDisAppearing);  
    52.   
    53.     //设置单个item间的动画间隔  
    54.     mTransitioner.setStagger(LayoutTransition.CHANGE_APPEARING, 30);  
    55.   
    56.     layoutTransitionGroup.setLayoutTransition(mTransitioner);  
    57. }  

    (2)、LayoutTransition设置监听

    LayoutTransition还给提供了一个监听函数:
    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. public void addTransitionListener(TransitionListener listener)  
    2. //其中:  
    3. public interface TransitionListener {  
    4.   public void startTransition(LayoutTransition transition, ViewGroup container,View view, int transitionType);  
    5.   public void endTransition(LayoutTransition transition, ViewGroup container,View view, int transitionType);  
    6. }  
    在任何类型的LayoutTransition开始和结束时,都会调用TransitionListener的startTransition和endTransition方法。 
    在TransitionListener中总共有四个参数:
    • LayoutTransition transition:当前的LayoutTransition实例
    • ViewGroup container:当前应用LayoutTransition的container
    • View view:当前在做动画的View对象
    • int transitionType:当前的LayoutTransition类型,取值有:APPEARING、DISAPPEARING、CHANGE_APPEARING、CHANGE_DISAPPEARING
    如果我们给上面的示例中的mTransitioner添加上addTransitionListener,然后打上log:
    [java] view plain copy
     在CODE上查看代码片派生到我的代码片
    1. mTransitioner.addTransitionListener(new LayoutTransition.TransitionListener() {  
    2.     @Override  
    3.     public void startTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType) {  
    4.   
    5.         Log.d("qijian","start:"+"transitionType:"+transitionType +"count:"+container.getChildCount() + "view:"+view.getClass().getName());  
    6.     }  
    7.   
    8.     @Override  
    9.     public void endTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType) {  
    10.         Log.d("qijian","end:"+"transitionType:"+transitionType +"count:"+container.getChildCount() + "view:"+view.getClass().getName());  
    11.     }  
    12. });  
    看添加动画时,Log的输出是怎样的:

    对应的Log输出为:


    先看添加第一个控件时:


    在startTransition中,除去transitionType:2的APPEARING所对应的动画以外,在transitionType:0所对应的CHANGE_APPEARING时竟然也传给了LinearLayout控件!
    同样,在插入第二个控件时,CHANGE_APPEARING事件也进行了上传和监听!
    同样在删除控件时,CHANGE_DISAPPEARING也是会上传给父控件的


    所对应的Log如下:


    所以这里的结论就是:在使用addTransitionListener监听LayoutTransition过程监听时,CHANGE_APPEARING和CHANGE_DISAPPEARING事件都会上传给父类控件! 

    源码在文章底部给出 
    到这里,这个系列的知识基本就讲完了,下一篇就是给大家讲讲第三方库nieOldAndroid的用法,做为Android animation动画系列的结尾。


    源码内容:
    1、《BlogAnimateLayoutChanges》:第一部分AnimateLayoutChanges属性所对应的代码
    2、《BlogLayoutTransition》:第二部分LayoutTransition所对应的代码


    如果本文有帮到你,记得加关注哦

    源码下载地址:http://download.csdn.net/download/harvic880925/9473049

    请大家尊重原创者版权,转载请标明出处:http://blog.csdn.net/harvic880925/article/details/50985596

  • 相关阅读:
    架构基础-容量评估
    golang版本实现版本号比较-从易到解决bug
    数组模拟栈
    稀疏数组
    密码生成器
    01-gopsutil包使用
    02从零开始学习GO语言--标识符、关键字、变量和常量
    Go语言简介
    从零开始学习GO语言-搭建Go语言开发环境-快速开发入门第一个小程序
    ES6学习总结之 Module
  • 原文地址:https://www.cnblogs.com/vegetate/p/9997292.html
Copyright © 2011-2022 走看看