android动画--animateLayoutChanges与LayoutTransition

2024-02-24 05:32

本文主要是介绍android动画--animateLayoutChanges与LayoutTransition,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原文地址:http://blog.csdn.net/harvic880925/article/details/50985596#t3

需要了解android动画详细的,推荐一个专题:http://blog.csdn.net/harvic880925/article/details/50995268

上一篇给大家讲了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  android:id="@+id/remove_btn"  android:layout_width="wrap_content"  android:layout_height="wrap_content"  android:text="移除控件"/>  </LinearLayout>  <LinearLayout  android:id="@+id/layoutTransitionGroup"  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:animateLayoutChanges="true"  android:orientation="vertical"/>  </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  android:id="@+id/remove_btn"  android:layout_width="wrap_content"  android:layout_height="wrap_content"  android:text="移除控件"/>  </LinearLayout>  <LinearLayout  android:id="@+id/layoutTransitionGroup"  android:layout_width="match_parent"  android:layout_height="wrap_content"  android:orientation="vertical"/>  </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事件都会上传给父类控件!

源码内容:请看原博客,支持原创。

这篇关于android动画--animateLayoutChanges与LayoutTransition的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/741088

相关文章

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

Android里面的Service种类以及启动方式

《Android里面的Service种类以及启动方式》Android中的Service分为前台服务和后台服务,前台服务需要亮身份牌并显示通知,后台服务则有启动方式选择,包括startService和b... 目录一句话总结:一、Service 的两种类型:1. 前台服务(必须亮身份牌)2. 后台服务(偷偷干

Android kotlin语言实现删除文件的解决方案

《Androidkotlin语言实现删除文件的解决方案》:本文主要介绍Androidkotlin语言实现删除文件的解决方案,在项目开发过程中,尤其是需要跨平台协作的项目,那么删除用户指定的文件的... 目录一、前言二、适用环境三、模板内容1.权限申请2.Activity中的模板一、前言在项目开发过程中,尤

最好用的WPF加载动画功能

《最好用的WPF加载动画功能》当开发应用程序时,提供良好的用户体验(UX)是至关重要的,加载动画作为一种有效的沟通工具,它不仅能告知用户系统正在工作,还能够通过视觉上的吸引力来增强整体用户体验,本文给... 目录前言需求分析高级用法综合案例总结最后前言当开发应用程序时,提供良好的用户体验(UX)是至关重要

基于Python实现PDF动画翻页效果的阅读器

《基于Python实现PDF动画翻页效果的阅读器》在这篇博客中,我们将深入分析一个基于wxPython实现的PDF阅读器程序,该程序支持加载PDF文件并显示页面内容,同时支持页面切换动画效果,文中有详... 目录全部代码代码结构初始化 UI 界面加载 PDF 文件显示 PDF 页面页面切换动画运行效果总结主

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO

Android WebView的加载超时处理方案

《AndroidWebView的加载超时处理方案》在Android开发中,WebView是一个常用的组件,用于在应用中嵌入网页,然而,当网络状况不佳或页面加载过慢时,用户可能会遇到加载超时的问题,本... 目录引言一、WebView加载超时的原因二、加载超时处理方案1. 使用Handler和Timer进行超

Qt QWidget实现图片旋转动画

《QtQWidget实现图片旋转动画》这篇文章主要为大家详细介绍了如何使用了Qt和QWidget实现图片旋转动画效果,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 一、效果展示二、源码分享本例程通过QGraphicsView实现svg格式图片旋转。.hpjavascript

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo