Home  >  Article  >  Web Front-end  >  Animation动画详解(十二)--animateLayoutChanges与LayoutTransition_html/css_WEB-ITnose

Animation动画详解(十二)--animateLayoutChanges与LayoutTransition_html/css_WEB-ITnose

WBOY
WBOYOriginal
2016-06-24 11:22:441350browse

前言:生活不只眼前的苟且,还有诗和远方的田野


相关文章:

1、《Animation 动画详解(一)——alpha、scale、translate、rotate、set的xml属性及用法》
2、《Animation动画详解(二)——Interpolator插值器》
3、《Animation动画详解(三)—— 代码生成alpha、scale、translate、rotate、set及插值器动画》
4、《Animation动画详解(四)——ValueAnimator基本使用》
5、《Animation动画详解(五)——ValueAnimator高级进阶(一)》
6、《Animation动画详解(六)——ValueAnimator高级进阶(二)》
7、《Animation动画详解(七)——ObjectAnimator基本使用》
8、《 Animation动画详解(八)——PropertyValuesHolder与Keyframe》
9、《 Animation动画详解(九)——联合动画的代码实现》
10、《Animation动画详解(十)——联合动画的XML实现与使用示例》
11、《 Animation动画详解(十一)——layoutAnimation与gridLayoutAnimation》
12、《Animation动画详解(十二)——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布局代码

<?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">    <linearlayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal">        <button android:id="@+id/add_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="添加控件"></button>        <button android:id="@+id/remove_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="移除控件"></button>    </linearlayout>    <linearlayout android:id="@+id/layoutTransitionGroup" android:layout_width="match_parent" android:layout_height="wrap_content" android:animatelayoutchanges="true" android:orientation="vertical"></linearlayout></linearlayout>
布局代码很简单,两个按钮,最底部是一个LinearLayout做为动态添加btn的container,注意,我们给它添加了android:animateLayoutChanges="true"也就是说,它内部的控件在添加和删除时,是会带有默认动画。

2、MyActivity代码

MyActivity的代码也很简单,就是在点击添加按钮时向其中动态添加一个btn,在点击删除按钮时,将其中第一个按钮给删除。
public class MyActivity extends Activity implements View.OnClickListener {    private LinearLayout layoutTransitionGroup;    private int i = 0;    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        layoutTransitionGroup = (LinearLayout) findViewById(R.id.layoutTransitionGroup);        findViewById(R.id.add_btn).setOnClickListener(this);        findViewById(R.id.remove_btn).setOnClickListener(this);    }    private void addButtonView() {        i++;        Button button = new Button(this);        button.setText("button" + i);        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,                ViewGroup.LayoutParams.WRAP_CONTENT);        button.setLayoutParams(params);        layoutTransitionGroup.addView(button, 0);    }    private void removeButtonView() {        if (i > 0) {            layoutTransitionGroup.removeViewAt(0);        }        i--;    }    @Override    public void onClick(View v) {        if (v.getId() == R.id.add_btn) {            addButtonView();        }        if (v.getId() == R.id.remove_btn) {            removeButtonView();        }    }}
代码很简单就不再细讲了。

由上面的效果图可见,我们只需要在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是非常容易的,只需要三步: 

第一步:创建实例

LayoutTransaction transitioner = new LayoutTransition();
第二步:创建动画并设置

ObjectAnimator animOut = ObjectAnimator.ofFloat(null, "rotation", 0f, 90f, 0f);transitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);
第三步:将LayoutTransaction设置进ViewGroup
linearLayout.setLayoutTransition(mTransitioner);
其中第三步中,在API 11之后,所有派生自ViewGroup类,比如LinearLayout,FrameLayout,RelativeLayout等,都具有一个专门用来设置LayoutTransition的方法:
public void setLayoutTransition(LayoutTransition transition)
在第二步中,transitioner.setAnimator设置动画的函数声明为:
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布局

    <?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">    <linearlayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal">        <button android:id="@+id/add_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="添加控件"></button>        <button android:id="@+id/remove_btn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="移除控件"></button>    </linearlayout>    <linearlayout android:id="@+id/layoutTransitionGroup" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"></linearlayout></linearlayout>
    布局代码与上面一样,但唯一不同的是在LinearLayout中没有android:animateLayoutChanges="true"
    然后是在MyActivity中的代码处理
    public class MyActivity extends Activity implements View.OnClickListener{    private LinearLayout layoutTransitionGroup;    private LayoutTransition mTransitioner;    private int i = 0;    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        layoutTransitionGroup = (LinearLayout) findViewById(R.id.layoutTransitionGroup);        findViewById(R.id.add_btn).setOnClickListener(this);        findViewById(R.id.remove_btn).setOnClickListener(this);        mTransitioner = new LayoutTransition();        //入场动画:view在这个容器中消失时触发的动画        ObjectAnimator animIn = ObjectAnimator.ofFloat(null, "rotationY", 0f, 360f,0f);        mTransitioner.setAnimator(LayoutTransition.APPEARING, animIn);        //出场动画:view显示时的动画        ObjectAnimator animOut = ObjectAnimator.ofFloat(null, "rotation", 0f, 90f, 0f);        mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);        layoutTransitionGroup.setLayoutTransition(mTransitioner);    }    private void addButtonView() {        i++;        Button button = new Button(this);        button.setText("button" + i);        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,                ViewGroup.LayoutParams.WRAP_CONTENT);        button.setLayoutParams(params);        layoutTransitionGroup.addView(button, 0);    }    private void removeButtonView() {        if (i > 0) {            layoutTransitionGroup.removeViewAt(0);        }        i--;    }    @Override    public void onClick(View v) {        if (v.getId() == R.id.add_btn) {            addButtonView();        }        if (v.getId() == R.id.remove_btn) {            removeButtonView();        }    }}
    同样是在点击“添加控件”按钮时,向LinearLayout中动态添加一个控件,在点击“移除控件”按钮时,将LinearLayout中第一个控件给移除。
    但是非常注意的是我们的LayoutTransition是在OnCreate中设置的,也就是说是在LinearLayout创建时就给它定义好控件的入场动画和出场动画的,定义代码如下:
    mTransitioner = new LayoutTransition();//入场动画:view在这个容器中消失时触发的动画ObjectAnimator animIn = ObjectAnimator.ofFloat(null, "rotationY", 0f, 360f,0f);mTransitioner.setAnimator(LayoutTransition.APPEARING, animIn);//出场动画:view显示时的动画ObjectAnimator animOut = ObjectAnimator.ofFloat(null, "rotation", 0f, 90f, 0f);mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);layoutTransitionGroup.setLayoutTransition(mTransitioner);
    代码难度不大,也就是我们这节开始时所讲的那三步:
    第一步,定义LayoutTransition实例:
    mTransitioner = new LayoutTransition();
    第二步:创建动画并设置
    //入场动画:view在这个容器中消失时触发的动画ObjectAnimator animIn = ObjectAnimator.ofFloat(null, "rotationY", 0f, 360f,0f);mTransitioner.setAnimator(LayoutTransition.APPEARING, animIn);//出场动画:view显示时的动画ObjectAnimator animOut = ObjectAnimator.ofFloat(null, "rotation", 0f, 90f, 0f);mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);
    分别定义了,当一个控件被插入时,这个被插入的控件所使用的动画:即绕Y轴旋转360度。
    ObjectAnimator animIn = ObjectAnimator.ofFloat(null, "rotationY", 0f, 360f,0f);mTransitioner.setAnimator(LayoutTransition.APPEARING, animIn);
    然后是当一个控件被移除时,这个被移除的控件所使用的动画:即绕Z轴旋转90度:
    ObjectAnimator animOut = ObjectAnimator.ofFloat(null, "rotation", 0f, 90f, 0f);mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);
    第三步:将LayoutTransaction设置进ViewGroup
    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所对应的完整代码
    public void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.main);    layoutTransitionGroup = (LinearLayout) findViewById(R.id.layoutTransitionGroup);    findViewById(R.id.add_btn).setOnClickListener(this);    findViewById(R.id.remove_btn).setOnClickListener(this);    mTransitioner = new LayoutTransition();    //入场动画:view在这个容器中消失时触发的动画    ObjectAnimator animIn = ObjectAnimator.ofFloat(null, "rotationY", 0f, 360f,0f);    mTransitioner.setAnimator(LayoutTransition.APPEARING, animIn);    //出场动画:view显示时的动画    ObjectAnimator animOut = ObjectAnimator.ofFloat(null, "rotation", 0f, 90f, 0f);    mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);    PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,100,0);    PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",1,1);    Animator changeAppearAnimator            = ObjectAnimator.ofPropertyValuesHolder(layoutTransitionGroup, pvhLeft,pvhBottom,pvhTop,pvhRight);    mTransitioner.setAnimator(LayoutTransition.CHANGE_APPEARING,changeAppearAnimator);    layoutTransitionGroup.setLayoutTransition(mTransitioner);}
    入场动画((LayoutTransition.APPEARING)和出场动画(LayoutTransition.DISAPPEARING)我们已经讲过了,下面我们主要看看入场时,其它控件位移动画的部分:
    PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,100,0);PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",1,1);Animator changeAppearAnimator        = ObjectAnimator.ofPropertyValuesHolder(layoutTransitionGroup, pvhLeft,pvhBottom,pvhTop,pvhRight);mTransitioner.setAnimator(LayoutTransition.CHANGE_APPEARING,changeAppearAnimator);
    这里有几点注意事项:
    1、LayoutTransition.CHANGE_APPEARING和LayoutTransition.CHANGE_DISAPPEARING必须使用PropertyValuesHolder所构造的动画才会有效果,不然无效!也就是说使用ObjectAnimator构造的动画,在这里是不会有效果的!
    2、在构造PropertyValuesHolder动画时,”left”、”top”属性的变动是必写的。如果不需要变动,则直接写为:
    PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,0);PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",0,0);
    3、在构造PropertyValuesHolder时,所使用的ofInt,ofFloat中的参数值,第一个值和最后一个值必须相同,不然此属性所对应的的动画将被放弃,在此属性值上将不会有效果;
    PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,100,0);
    比如,这里ofInt(“left”,0,100,0)第一个值和最后一个值都是0,所以这里会有效果的,如果我们改为ofInt(“left”,0,100);那么由于首尾值不一致,则将被视为无效参数,将不会有效果!
    4、在构造PropertyValuesHolder时,所使用的ofInt,ofFloat中,如果所有参数值都相同,也将不会有动画效果。
    比如:
    PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",100,100);
    在这条语句中,虽然首尾一致,但由于全程参数值相同,所以left属性上的这个动画会被放弃,在left属性上也不会应用上任何动画。
    看到了吧,坑就是如此多,至于这些都是为什么,我也懒得去研究它的源码,因为LayoutTransition的问题实在是太!多!了!至于这篇文章嘛,由于这是一个Android 动画的系列,而LayoutTransition也是其中一员,本着尊重知识的原则,还是给大家讲一讲,至于应用嘛!呵呵,慎用之……
    我们上面讲了,left,top属性是必须的,下面我们给他扩展一下,除了给它添加left,top属性以外,再给它加上scale属性,让它同时放大,代码即:
    PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,100,0);PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",1,1);PropertyValuesHolder pvhScaleX = PropertyValuesHolder.ofFloat("ScaleX",1f,9f,1f);Animator changeAppearAnimator       = ObjectAnimator.ofPropertyValuesHolder(layoutTransitionGroup, pvhLeft,pvhTop,pvhScaleX);mTransitioner.setAnimator(LayoutTransition.CHANGE_APPEARING,changeAppearAnimator);
    对应动画效果为:

    (2)、LayoutTransition.CHANGE_DISAPPEARING实现

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

    PropertyValuesHolder outLeft = PropertyValuesHolder.ofInt("left",0,0);PropertyValuesHolder outTop = PropertyValuesHolder.ofInt("top",0,0);Keyframe frame0 = Keyframe.ofFloat(0f, 0);Keyframe frame1 = Keyframe.ofFloat(0.1f, -20f);Keyframe frame2 = Keyframe.ofFloat(0.2f, 20f);Keyframe frame3 = Keyframe.ofFloat(0.3f, -20f);Keyframe frame4 = Keyframe.ofFloat(0.4f, 20f);Keyframe frame5 = Keyframe.ofFloat(0.5f, -20f);Keyframe frame6 = Keyframe.ofFloat(0.6f, 20f);Keyframe frame7 = Keyframe.ofFloat(0.7f, -20f);Keyframe frame8 = Keyframe.ofFloat(0.8f, 20f);Keyframe frame9 = Keyframe.ofFloat(0.9f, -20f);Keyframe frame10 = Keyframe.ofFloat(1, 0);PropertyValuesHolder mPropertyValuesHolder = PropertyValuesHolder.ofKeyframe("rotation",frame0,frame1,frame2,frame3,frame4,frame5,frame6,frame7,frame8,frame9,frame10);ObjectAnimator mObjectAnimatorChangeDisAppearing = ObjectAnimator.ofPropertyValuesHolder(this, outLeft,outTop,mPropertyValuesHolder);mTransitioner.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, mObjectAnimatorChangeDisAppearing);
    第一步:由于left,top属性是必须的,但我们做响铃效果时,是不需要Left,top变动的,所有给他们设置为无效值:(看到了没,必须设置的意思就是即使设置的值是无效的,也要设置!不然就会由于Left,top属性没有设置而整个PropertyValuesHolder动画无效,好恶心的用法……大家可以在源码注掉哪句话,或者把上面的所有无效设置尝试一遍,看看效果便知)
    PropertyValuesHolder outLeft = PropertyValuesHolder.ofInt("left",0,0);PropertyValuesHolder outTop = PropertyValuesHolder.ofInt("top",0,0);
    第二步:用KeyFrame构造PropertyValuesHolder
    Keyframe frame0 = Keyframe.ofFloat(0f, 0);Keyframe frame1 = Keyframe.ofFloat(0.1f, -20f);Keyframe frame2 = Keyframe.ofFloat(0.2f, 20f);Keyframe frame3 = Keyframe.ofFloat(0.3f, -20f);Keyframe frame4 = Keyframe.ofFloat(0.4f, 20f);Keyframe frame5 = Keyframe.ofFloat(0.5f, -20f);Keyframe frame6 = Keyframe.ofFloat(0.6f, 20f);Keyframe frame7 = Keyframe.ofFloat(0.7f, -20f);Keyframe frame8 = Keyframe.ofFloat(0.8f, 20f);Keyframe frame9 = Keyframe.ofFloat(0.9f, -20f);Keyframe frame10 = Keyframe.ofFloat(1, 0);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动画
    ObjectAnimator mObjectAnimatorChangeDisAppearing = ObjectAnimator.ofPropertyValuesHolder(this, outLeft,outTop,mPropertyValuesHolder);mTransitioner.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, mObjectAnimatorChangeDisAppearing);

    对应效果为:


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

    public void onCreate(Bundle savedInstanceState) {   super.onCreate(savedInstanceState);   setContentView(R.layout.main);   layoutTransitionGroup = (LinearLayout) findViewById(R.id.layoutTransitionGroup);   findViewById(R.id.add_btn).setOnClickListener(this);   findViewById(R.id.remove_btn).setOnClickListener(this);   mTransitioner = new LayoutTransition();   //入场动画:view在这个容器中消失时触发的动画   ObjectAnimator animIn = ObjectAnimator.ofFloat(null, "rotationY", 0f, 360f,0f);   mTransitioner.setAnimator(LayoutTransition.APPEARING, animIn);   //出场动画:view显示时的动画   ObjectAnimator animOut = ObjectAnimator.ofFloat(null, "rotation", 0f, 90f, 0f);   mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);   /**    * LayoutTransition.CHANGE_APPEARING动画    */   PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,100,0);   PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",1,1);   //必须第一个值与最后一值相同才会有效果,不然没有效果   PropertyValuesHolder pvhScaleX = PropertyValuesHolder.ofFloat("ScaleX",1f,9f,1f);   Animator changeAppearAnimator           = ObjectAnimator.ofPropertyValuesHolder(layoutTransitionGroup, pvhLeft,pvhTop,pvhScaleX);   mTransitioner.setAnimator(LayoutTransition.CHANGE_APPEARING,changeAppearAnimator);   /**    * LayoutTransition.CHANGE_DISAPPEARING动画    */   PropertyValuesHolder outLeft = PropertyValuesHolder.ofInt("left",0,0);   PropertyValuesHolder outTop = PropertyValuesHolder.ofInt("top",0,0);   Keyframe frame0 = Keyframe.ofFloat(0f, 0);   Keyframe frame1 = Keyframe.ofFloat(0.1f, -20f);   Keyframe frame2 = Keyframe.ofFloat(0.2f, 20f);   Keyframe frame3 = Keyframe.ofFloat(0.3f, -20f);   Keyframe frame4 = Keyframe.ofFloat(0.4f, 20f);   Keyframe frame5 = Keyframe.ofFloat(0.5f, -20f);   Keyframe frame6 = Keyframe.ofFloat(0.6f, 20f);   Keyframe frame7 = Keyframe.ofFloat(0.7f, -20f);   Keyframe frame8 = Keyframe.ofFloat(0.8f, 20f);   Keyframe frame9 = Keyframe.ofFloat(0.9f, -20f);   Keyframe frame10 = Keyframe.ofFloat(1, 0);   PropertyValuesHolder mPropertyValuesHolder = PropertyValuesHolder.ofKeyframe("rotation",frame0,frame1,frame2,frame3,frame4,frame5,frame6,frame7,frame8,frame9,frame10);   ObjectAnimator mObjectAnimatorChangeDisAppearing = ObjectAnimator.ofPropertyValuesHolder(this, outLeft,outTop,mPropertyValuesHolder);   mTransitioner.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, mObjectAnimatorChangeDisAppearing);   layoutTransitionGroup.setLayoutTransition(mTransitioner);}   

    源码在文章底部给出

    4、其它函数

    (1)、基本设置

    上面我们讲了LayoutTransition的setAnimator方法,在LayoutTransition中还有一些其它方法,下面我们来讲解下:
    /** * 设置所有动画完成所需要的时长 */public void setDuration(long duration)/** * 针对单个type,设置动画时长; * transitionType取值为:APPEARING、DISAPPEARING、CHANGE_APPEARING、CHANGE_DISAPPEARING */public void setDuration(int transitionType, long duration) /** * 针对单个type设置插值器 * transitionType取值为:APPEARING、DISAPPEARING、CHANGE_APPEARING、CHANGE_DISAPPEARING */public void setInterpolator(int transitionType, TimeInterpolator interpolator)/** * 针对单个type设置动画延时 * transitionType取值为:APPEARING、DISAPPEARING、CHANGE_APPEARING、CHANGE_DISAPPEARING */public void setStartDelay(int transitionType, long delay)/** * 针对单个type设置,每个子item动画的时间间隔 */public void setStagger(int transitionType, long duration)
    除了setStagger以外,如果你把我的Animation系列一路看下来的话,其它这些函数理解起来只能说so easy,这里就不再举例了,下面我们讲讲setStagger用法与效果
    我们还回来看看上面的效果图:

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

    mTransitioner.setStagger(LayoutTransition.CHANGE_APPEARING, 30);
    动画效果为:

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

    public void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.main);    layoutTransitionGroup = (LinearLayout) findViewById(R.id.layoutTransitionGroup);    findViewById(R.id.add_btn).setOnClickListener(this);    findViewById(R.id.remove_btn).setOnClickListener(this);    mTransitioner = new LayoutTransition();    //入场动画:view在这个容器中消失时触发的动画    ObjectAnimator animIn = ObjectAnimator.ofFloat(null, "rotationY", 0f, 360f,0f);    mTransitioner.setAnimator(LayoutTransition.APPEARING, animIn);    //出场动画:view显示时的动画    ObjectAnimator animOut = ObjectAnimator.ofFloat(null, "rotation", 0f, 90f, 0f);    mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);    /**     * LayoutTransition.CHANGE_APPEARING动画     */    PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left",0,100,0);    PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",1,1);    //必须第一个值与最后一值相同才会有效果,不然没有效果    PropertyValuesHolder pvhScaleX = PropertyValuesHolder.ofFloat("ScaleX",1f,9f,1f);    Animator changeAppearAnimator            = ObjectAnimator.ofPropertyValuesHolder(layoutTransitionGroup, pvhLeft,pvhTop,pvhScaleX);    mTransitioner.setAnimator(LayoutTransition.CHANGE_APPEARING,changeAppearAnimator);    /**     * LayoutTransition.CHANGE_DISAPPEARING动画     */    PropertyValuesHolder outLeft = PropertyValuesHolder.ofInt("left",0,0);    PropertyValuesHolder outTop = PropertyValuesHolder.ofInt("top",0,0);    Keyframe frame0 = Keyframe.ofFloat(0f, 0);    Keyframe frame1 = Keyframe.ofFloat(0.1f, -20f);    Keyframe frame2 = Keyframe.ofFloat(0.2f, 20f);    Keyframe frame3 = Keyframe.ofFloat(0.3f, -20f);    Keyframe frame4 = Keyframe.ofFloat(0.4f, 20f);    Keyframe frame5 = Keyframe.ofFloat(0.5f, -20f);    Keyframe frame6 = Keyframe.ofFloat(0.6f, 20f);    Keyframe frame7 = Keyframe.ofFloat(0.7f, -20f);    Keyframe frame8 = Keyframe.ofFloat(0.8f, 20f);    Keyframe frame9 = Keyframe.ofFloat(0.9f, -20f);    Keyframe frame10 = Keyframe.ofFloat(1, 0);    PropertyValuesHolder mPropertyValuesHolder = PropertyValuesHolder.ofKeyframe("rotation",frame0,frame1,frame2,frame3,frame4,frame5,frame6,frame7,frame8,frame9,frame10);    ObjectAnimator mObjectAnimatorChangeDisAppearing = ObjectAnimator.ofPropertyValuesHolder(this, outLeft,outTop,mPropertyValuesHolder);    mTransitioner.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, mObjectAnimatorChangeDisAppearing);    //设置单个item间的动画间隔    mTransitioner.setStagger(LayoutTransition.CHANGE_APPEARING, 30);    layoutTransitionGroup.setLayoutTransition(mTransitioner);}

    (2)、LayoutTransition设置监听

    LayoutTransition还给提供了一个监听函数:
    public void addTransitionListener(TransitionListener listener)//其中:public interface TransitionListener {  public void startTransition(LayoutTransition transition, ViewGroup container,View view, int transitionType);  public void endTransition(LayoutTransition transition, ViewGroup container,View view, int transitionType);}
    在任何类型的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:
    mTransitioner.addTransitionListener(new LayoutTransition.TransitionListener() {    @Override    public void startTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType) {        Log.d("qijian","start:"+"transitionType:"+transitionType +"count:"+container.getChildCount() + "view:"+view.getClass().getName());    }    @Override    public void endTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType) {        Log.d("qijian","end:"+"transitionType:"+transitionType +"count:"+container.getChildCount() + "view:"+view.getClass().getName());    }});
    看添加动画时,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

    请大家尊重原创者版权,转载请标明出处:


    Statement:
    The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn