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

Android Animation学习(五) ApiDemos解析:容器布局动画 LayoutTransition的更多相关文章

  1. Android Animation学习(二) ApiDemos解析:基本Animators使用

    Android Animation学习(二) ApiDemos解析:基本Animatiors使用 Animator类提供了创建动画的基本结构,但是一般使用的是它的子类: ValueAnimator.O ...

  2. Android Animation学习(二) ApiDemos解析:基本Animatiors使用

    Animator类提供了创建动画的基本结构,但是一般使用的是它的子类: ValueAnimator.ObjectAnimator.AnimatorSet ApiDemos中Animation部分是单独 ...

  3. Android Animation学习(三) ApiDemos解析:XML动画文件的使用

    Android Animation学习(三) ApiDemos解析:XML动画文件的使用 可以用XML文件来定义Animation. 文件必须有一个唯一的根节点: <set>, <o ...

  4. Android Animation学习(四) ApiDemos解析:多属性动画

    Android Animation学习(四) ApiDemos解析:多属性动画 如果想同时改变多个属性,根据前面所学的,比较显而易见的一种思路是构造多个对象Animator , ( Animator可 ...

  5. Android Animation学习(六) View Animation介绍

    Android Animation学习(六) View Animation介绍 View Animation View animation系统可以用来执行View上的Tween animation和F ...

  6. Android Animation学习(一) Property Animation原理介绍和API简介

    Android Animation学习(一) Property Animation介绍 Android Animation Android framework提供了两种动画系统: property a ...

  7. Android JNI学习(五)——Demo演示

    本系列文章如下: Android JNI(一)——NDK与JNI基础 Android JNI学习(二)——实战JNI之“hello world” Android JNI学习(三)——Java与Nati ...

  8. Android Animation学习笔记

    原文地址: http://www.cnblogs.com/feisky/archive/2010/01/11/1644482.html 关于动画的实现,Android提供了Animation,在And ...

  9. Android Animation学习(一) Property Animation介绍

    Android Animation Android framework提供了两种动画系统: property animation (introduced in Android 3.0)和view an ...

随机推荐

  1. 聚合索引(clustered index) / 非聚合索引(nonclustered index)

    以下我面试经常问的2道题..尤其针对觉得自己SQL SERVER 还不错的同志.. 呵呵 很难有人答得好.. 各位在我收集每个人擅长的东西时,大部分都把SQL SERVER 标为Expert,看看是否 ...

  2. 深入分析MVC中通过IOC实现Controller依赖注入的原理

    这几天利用空闲时间,我将ASP.NET反编译后的源代码并结合园子里几位大侠的写的文章认真的看了一遍,收获颇丰,同时也摘要了一些学习内容,存入了该篇文章:<ASP.NET运行机制图解>,在对 ...

  3. CSS魔法堂:重新认识Box Model、IFC、BFC和Collapsing margins

    前言   盒子模型作为CSS基础中的基础,曾一度以为掌握了IE和W3C标准下的块级盒子模型即可,但近日在学习行级盒子模型时发现原来当初是如此幼稚可笑.本文尝试全面叙述块级.行级盒子模型的特性.作为近日 ...

  4. Java魔法堂:解读基于Type Erasure的泛型

    一.前言 还记得JDK1.4时遍历列表的辛酸吗?我可是记忆犹新啊,那时因项目需求我从C#转身到Java的怀抱,然后因JDK1.4少了泛型这样语法糖(还有自动装箱.拆箱),让我受尽苦头啊,不过也反映自己 ...

  5. JS魔法堂:从void 0 === undefined说起

    一.前言 当使用coffeescript书写如下代码时 name = person?.name 会被预编译为 ; ,那么void 0到底是什么意思呢?运行得知void 0===undefined为tr ...

  6. ASP.NET MVC程序播放H.264视频

    在这篇之前,Insus.NET不管是在ASP.NET还是ASP.NET MVC实现很多视频播放,你可以参考这篇链接:http://www.cnblogs.com/insus/category/4650 ...

  7. MySQL Error Handling in Stored Procedures

    http://www.mysqltutorial.org/mysql-error-handling-in-stored-procedures/ mysql存储过程中的异常处理   定义异常捕获类型及处 ...

  8. Spring注解@Value的用法

    有时候我们在配置文件中使用配置的信息不仅需要在xml文件中使用,还可能在类中使用,这个时候,我们可使用@Value注解了: @Value("${rest.service.url}" ...

  9. tps (事务处理系统)

    事务处理系统:Transaction processing systems (TPS) 提高事务处理效率与保证其正确性 在数据(信息)发生处将它们记录下来 通过OLTP产生新的信息 将信息保存到数据库 ...

  10. javamail 利用qq邮箱做邮箱服务器,简单小demo

    首先maven: <dependency> <groupId>javax.mail</groupId> <artifactId>mail</art ...