Android 属性动画 详解

Android 属性动画 详解

Android动画类型:
View Animation(即所谓的Tween Animation补间动画):View Animation相当简单,不过只能支持简单的缩放、平移、旋转、透明度基本的动画
Drawable Animation (即所谓Frame Animation逐帧动画)
Property Animation 利用对象的属性变化形成动画的效果
Tween Animation和Frame Animation的动态效果只适应一个控件,或者说多个控件同时执行一种效果。
Property Animation可同时对一个对象应用多个动画,动画期间可以进行交互设置。

Property Animation 和 View Animation的区别
1、View Animation只能用于View及View的子类的对象;Property Animation则没有这样的限制
2、View Animation限制较多,一些动画,只能用于没有background的view,否则会打不到预期效果;如缩放一个view时,这是缩小了view的外观,她的background并没有改变,所以如果background不是透明的,则会露馅。
3、View Animation只是简单的改变View的绘制,并不会改变View本身。比如,你将一个button从位置1移动到位置2,但是触发点击事件的位置还是在位置1。Property Animation这不会出现这种情况。
View Animation使用的代码较少,启动所花费的时间也短

PropertyAnimation
属性动画,就是利用对象的属性变化形成动画的效果。
属性动画的类可以用Animator这个抽象类来表示,通常使用它的子类:AnimatorSet和ValueAnimator,
同时ValueAnimator有两个子类分别是ObjectAniamtor和TimeAnimator。

1、定义属性动画的XML资源的时候通常可以是如下三个元素之一作为根元素:
<set>元素:
—该资源元素代表的是AniamtorSet类:动画集合,即同时对一个对象应用多个动画,这些动画可以同时播放也可以对不同动画设置不同的延迟
这个类可以包含<set>,<objectAniamtor>, <animator>三个子元素。
<objectAnimator>元素:
—用于定义objectAniamtor类,一个对象的一个属性动画。
<animator>元素:
—用于定义ValueAnimator类,在一个特定的时间里执行一个动画。
<set> <objectAniamtor> <animator>定义此三种元素的xml文件必须位于res/animator目录下

<set android:ordering="[together|sequentially]"> // 控制子动画启动顺序:默认(together)同时启动,sequentially按先后顺序启动
    <objectAnimator
        android:propertyName="string" 
        //要执行动画的属性名,如"alpha" "backgroundColor" 
        android:duration="int"   
        //int型,动画的持续时间,单位毫秒,默认为300毫秒
        android:valueFrom="float|int|color" //float int color类型,动画的起始点,若没有指定,系统会通过属性的get方法获取,颜色为6位十六进制的数字表示
        android:valueTo="float|int|color"
//float int color类型,必须设置的节点属性,表明动画的结束点,如果是颜色的话,由6位十六进制的数字表示
        android:startOffset="int" 
//int型,动画延迟时间,从调用start方法后开始计算,单位毫秒
        android:repeatCount="int" 
//int型,动画重复次数,默认为0,不重复执行,"-1"无线循环,"1"动画执行完后再重复执行一次
        android:interpolator="" 
//定义动画变化速率的接口,所有插值器都必须实现此接口,如线性、非线性插值器
        android:repeatMode="[reapeat|reverse]" // int型,重复模式,该值必须为正数或-1,"reverse"动画向相反的方向执行、"repeat"动画每次都从头开始循环
        android:valueType="[intType|floatType]"/> // intType和floatType两种:分别说明动画值为int和float型,若value是一个颜色,就不需指定,动画框架会自动处理颜色值
    <animator      
        android:duration="int"
        android:valueFrom="float|int|color"
        android:valueTo="float|int|color"
        android:startOffset="int"
        android:repeatCount="int"
        android:interpolator=""
        android:repeatMode="[reapeat|reverse]"
        android:valueType="[intType|floatType]"/>
    <set>
        ....
    </set>    
</set>

//示例
//res/animator/animSet.xml

<set xmlns:android="http://schemas.android.com/apk/res/android"  
    android:ordering="sequentially" >  
    <objectAnimator  
        android:duration="2000"  
        android:propertyName="translationX"  
        android:valueFrom="-500"  
        android:valueTo="0"  
        android:valueType="floatType" >  
    </objectAnimator>   
    <set android:ordering="together" >  
        <objectAnimator  
            android:duration="3000"  
            android:propertyName="rotation"  
            android:valueFrom="0"  
            android:valueTo="360"  
            android:valueType="floatType" >  
        </objectAnimator>  
        <set android:ordering="sequentially" >  
            <objectAnimator  
                android:duration="1500"  
                android:propertyName="alpha"  
                android:valueFrom="1"  
                android:valueTo="0"  
                android:valueType="floatType" >  
            </objectAnimator>  
            <objectAnimator  
                android:duration="1500"  
                android:propertyName="alpha"  
                android:valueFrom="0"  
                android:valueTo="1"  
                android:valueType="floatType" >  
            </objectAnimator>  
        </set>  
    </set>  
</set> 

//代码访问

Animator animator = AnimatorInflater.loadAnimator(context, R.animator.animSet);  
animator.setTarget(view);  
animator.start();  

ValueAnimator
属性动画中的时间驱动,管理着动画时间的开始、结束属性值,相应时间属性值计算方法等。
包含所有计算动画值的核心函数以及每一个动画时间节点上的信息、一个动画是否重复、是否监听更新事件等,并且还可以设置自定义的计算类型。
ValueAnimator有工厂方法ofInt()、ofFloat()、ofObject()用于不同的类型

ValueAnimator animator = ValueAnimator.ofFloat(0, mContentHeight);  
animator.setTarget(view);   //设置作用目标
animator.setDuration(5000).start();
//ValueAnimator.AnimatorUpdateListener
animator.addUpdateListener(new AnimatorUpdateListener() { // ValueAnimator没有设置属性,需要通过updateListener里设置属性才会生效。
    @Override
    public void onAnimationUpdate(ValueAnimator animation){ 
    //通过当前动画的计算去修改任何属性 ,帧刷新时调用,用于使用ValueAnimator计算出的属性值
        float value = (float) animation.getAnimatedValue();
        view.setXXX(value);  //必须通过这里设置属性值才有效,ValueAnimator不直接操作属性值,所以要操作对象的属性可以不需要setXXX与getXXX方法
        view.mXXX = value;  //不需要setXXX属性方法
    }
});

ObjectAnimator
1、继承自ValueAnimator,允许你指定要进行动画的对象以及该对象的一个属性。该类会根据计算得到的新值自动更新属性(不同于ValueAnimator,ValueAnimator需另写动画更新逻辑),
2、ObjectAnimator使用有一定的限制,它需要目标对象的属性提供指定的处理方法(譬如提供getXXX,setXXX方法)。
3、ObjectAnimator类提供了ofInt、ofFloat、ofObject这个三个常用的方法,这些方法都是设置动画作用的元素、属性、开始、结束等任意属性值,
当属性值(上面方法的参数)只设置一个时就把通过getXXX反射获取的值作为起点,设置的值作为终点;如果设置两个(参数),那么一个是开始、另一个是结束。
ObjectAnimator的动画原理是不停的调用setXXX方法更新属性值,所有使用ObjectAnimator更新属性时的前提是Object必须声明有getXXX和setXXX方法。
通常使用ObjectAnimator设置View已知的属性来生成动画,而一般View已知属性变化时都会主动触发重绘图操作,所以动画会自动实现
使用示例:
a: xml + 代码
//res/animator/objectColor => ObjectAnimator xml设置

<?xml version="1.0" encoding="utf-8"?>
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="5000"
    android:propertyName="backgroundColor"
    android:repeatCount="infinite"
    android:repeatMode="reverse"
    android:valueFrom="#ff8080"
    android:valueTo="#8080ff"
    android:valueType="intType" >
</objectAnimator>

//ObjectAnimator操作代码

ObjectAnimator oa = (ObjectAnimator) AnimatorInflater.loadAnimator(this, R.animator.objectColor); /加载属性动画需要用到AnimatorInflater类
oa.setEvaluator(new ArgbEvaluator()); //用于动画计算的需要,如果开始和结束的值不是基本类型的时候,这个方法是需要的。
oa.setTarget(imageView); //设置动画的设置目标
oa.start();

//res/animator/objectScale => ObjectAnimator xml设置

<?xml version="1.0" encoding="utf-8"?> 
<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android" 
    android:duration="1000" 
    android:propertyName="scaleX"  
    android:valueFrom="1.0" 
    android:valueTo="2.0" 
    android:valueType="floatType"> 
</objectAnimator> 

//ObjectAnimator操作代码
Animator anim = AnimatorInflater.loadAnimator(this,R.animator.objectScale); 
anim.setTarget(view); 
anim.start(); 

b:纯代码定义、使用

ObjectAnimator.ofFloat(view, "rotationY", 0.0f, 360.0f).setDuration(1000).start();
float curTranslationX = textview.getTranslationX();  
ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "translationX", curTranslationX, -500f, curTranslationX);  
//ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "scaleY", 1f, 3f, 1f); 
animator.setDuration(5000);  
animator.start();  
ObjectAnimator mObjectAnimator= ObjectAnimator.ofInt(view, "customerDefineAnyThingName", 0,  1) .setDuration(2000);

//若Object不是View,或者设置的属性没有触发重绘,或者在重绘时需要做自己的操作,则可以通过addUpdateListener()方法添加AnimatorUpdateListener监听:
mObjectAnimator.addUpdateListener(new AnimatorUpdateListener() {
     @Override
     public void onAnimationUpdate(ValueAnimator animation) {
         //int value = animation.getAnimatedValue();  可以获取当前属性值
         //view.postInvalidate();  可以主动刷新
         //view.setXXX(value);
         //view.setXXX(value);
         //......可以批量修改属性
     }
});

ObjectAnimator anim = ObjectAnimator.ofFloat(view, "op", 1.0F,  0.0F).setDuration(500); // "op", 设置的属性不会触发重绘
anim.start();  
anim.addUpdateListener(new AnimatorUpdateListener()  {   
     @Override  
     public void onAnimationUpdate(ValueAnimator animation)  {  //动画更新监听事件中,对view进行操作,触发view的重绘
         float cVal = (Float) animation.getAnimatedValue();  
         view.setAlpha(cVal);  
         view.setScaleX(cVal);  
         view.setScaleY(cVal);  
     }  
});

PropertyValuesHolder
多属性动画同时工作管理类。有时候我们需要同时修改多个属性,那就可以用到此类–针对同一个对象的多个属性,要同时作用多种动画。
ValueAnimator和ObjectAnimator的ofPropertyValuesHolder(view,…)可实现多属性动画

//平移的过程中同时改变XY轴的缩放,
PropertyValuesHolder pvh1 = PropertyValuesHolder.ofFloat("translationX", 300); 
PropertyValuesHolder pvh2 = PropertyValuesHolder.ofFloat("scaleX", 1f, 0, 1f); 
PropertyValuesHolder pvh3 = PropertyValuesHolder.ofFloat("scaleY", 1f, 0, 1f); 
ObjectAnimator.ofPropertyValuesHolder(view, pvh1, pvh2, pvh3).setDuration(1000).start(); //可以实现同时修改多个属性的动画
//移动过程中渐进显示
PropertyValuesHolder a1 = PropertyValuesHolder.ofFloat("alpha", 0f, 1f);
PropertyValuesHolder a2 = PropertyValuesHolder.ofFloat("translationY", 0, viewWidth);
......
ObjectAnimator.ofPropertyValuesHolder(view, a1, a2, ......).setDuration(1000).start(); // 可以实现同时修改多个属性的动画

AnimatorSet
对于一个对象同时作用多个属性动画效果,同时也能实现更为精确的顺序控制。

ObjectAnimator objectAnimator = ObjectAnimator.ofFloat(imageView, "translationX", 300f); 
ObjectAnimator objectAnimator1 = ObjectAnimator.ofFloat(imageView, "scaleX", 1f, 0f, 1f); 
ObjectAnimator objectAnimator2 = ObjectAnimator.ofFloat(imageView, "scaleY", 1f, 0f, 1f); 
AnimatorSet animatorSet = new AnimatorSet(); 
animatorSet.setDuration(1000); 
animatorSet.playTogether(objectAnimator, objectAnimator1, objectAnimator2); 
//animatorSet.play(objectAnimator).with(objectAnimator1);  
//animatorSet.play(objectAnimator1).with(objectAnimator2);       
animatorSet.start();  

ObjectAnimator moveIn = ObjectAnimator.ofFloat(textview, "translationX", -500f, 0f);  
ObjectAnimator rotate = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);  
ObjectAnimator fadeInOut = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);  
AnimatorSet animSet = new AnimatorSet();  
animSet.play(rotate).with(fadeInOut).after(moveIn);  
animSet.setDuration(5000);  
animSet.start();

在属性动画中,AnimatorSet正是通过playTogether()、playSquentially()、play().width()、play().defore()、play().after()支持链式编程这些方法来控制多个动画的协同工作方式,从而做到对动画播放顺序的精确控制。

AnimatorListener / AnimatorListenerAdapter
一个完整的动画具有Start、Repeat、End、Cancel四个过程,动画事件的监听:通过Android接口AnimatorListener,AnimatorListenerAdapter:

ObjectAnimator anim = ObjectAnimator.ofFloat(imageView, "alpha", 0.5F); 
anim.addListener(new Animator.AnimatorListener() { 
    @Override 
    public void onAnimationStart(Animator animation) { 
    } 
    @Override 
    public void onAnimationEnd(Animator animation) { 
    } 
    @Override 
    public void onAnimationCancel(Animator animation) { 
    } 
    @Override 
    public void onAnimationRepeat(Animator animation) { 
    } 
}); 
或使用AnimatorListenerAdapter,AnimatorListenerAdapter使用空方法实现了AnimatorListener的所有方法
anim.addListener(new AnimatorListenerAdapter() { 
    @Override 
    public void onAnimationEnd(Animator animation) {
        super.onAnimationEnd(animation); 
    } 
});
anim.start();  

Evaluators
Evaluators就是属性动画系统如何去计算一个属性值。它们通过Animator提供的
动画的起始和结束值去计算一个动画的属性值。
IntEvaluator: 整数属性值。
FloatEvaluator:浮点数属性值。
ArgbEvaluator: 十六进制color属性值。
TypeEvaluator: 用于定义属性值计算方式的接口,有int、float、color类型,根据属性的起始、结束值和插值一起计算出当前时间的属性值
//TypeEvaluator接口代码

public interface TypeEvaluator<T> {
    //根据动画进度,属性起始值和结束值,计算出当前值
    public T evaluate(float fraction, T startValue, T endValue);
}

Interpolators
插值器可以定义动画变换速率,主要是控制目标变量的值进行对应的变化。
AccelerateDecelerateInterpolator —先加速后减速,在动画开始与结束的地方速率改变比较慢,在中间的时候加速
AccelerateInterpolator —加速,在动画开始的地方速率改变比较慢,然后开始加速
DecelerateInterpolator —减速,在动画开始的地方快然后慢
AnticipateInterpolator —先向相反方向改变一段再加速播放
AnticipateOvershootInterpolator —先向相反方向改变,再加速播放,会超出目标值然后缓慢移动至目标值,类似于弹簧回弹
BounceInterpolator —动画结束的时候弹起,快到目标值时值会跳跃
CycleInterpolator —动画循环播放特定的次数,速率改变沿着正弦曲线,值的改变为一正弦函数:Math.sin(2 * mCycles * Math.PI * input)
LinearInterpolator —以常量速率改变,线性均匀改变
OvershootInterpolator —最后超出目标值然后缓慢改变到目标值,类似弹簧效果
PathInterpolator —路径插值器
TimeInterpolator:一个允许自定义Interpolator的接口,以上都实现了该接口

使用示例:

ValueAnimator valueAnimator = new ValueAnimator();
valueAnimator.setDuration(5000);
valueAnimator.setObjectValues(new float[2]); //设置属性值类型
valueAnimator.setInterpolator(new LinearInterpolator());
valueAnimator.setEvaluator(new TypeEvaluator<float[]>() {
    @Override
    public float[] evaluate(float fraction, float[] startValue,float[] endValue)
    {
        //实现自定义规则计算的float[]类型的属性值
        float[] temp = new float[2];
        temp[0] = fraction * 2;
        temp[1] = (float)Math.random() * 10 * fraction;
        return temp;
    }
});
valueAnimator.start();
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    @Override
    public void onAnimationUpdate(ValueAnimator animation) {
        float[] xyPos = (float[]) animation.getAnimatedValue();
        view.setHeight(xyPos[0]);   //通过属性值设置View属性动画
        view.setWidth(xyPos[1]);    //通过属性值设置View属性动画
    }
});

Keyframes关键帧
一个Keyframe对象有一个time/value对组成,用于指定在特定时间点,动画的状态。每一个关键帧都可以有它自己的插值器,用来控制前一个关键帧和此关键帧的关系。
1、使用方法ofInt(), ofFloat(), 和ofObject()中的一个来获得一个关键帧实例。
2、然后调用PropertyValuesHolder的工厂方法ofKeyframe()来获得一个PropertyValuesHolder对象。
3、将PropertyValuesHolder对象作为ObjectAnimator.ofPropertyValuesHolder()方法的参数,即可构造出一个对象。
示例

Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);
Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation);
rotationAnim.setDuration(5000ms);

ViewPropertyAnimator
动画是属性动画的拓展,在Android API 12中,View添加了animate方法,具体如下:

public class View implements Drawable.Callback, KeyEvent.Callback,AccessibilityEventSource {
    ...
    public ViewPropertyAnimator animate() {
        if (mAnimator == null) {
            mAnimator = new ViewPropertyAnimator(this); //当前视图的视图属性动画
        }
        return mAnimator;
    }
    ...
}

通过View的animate()方法可以得到一个ViewPropertyAnimator的属性动画,ViewPropertyAnimator提供了一种非常方便的方法为View的部分属性设置动画,它可以直接使用一个Animator对象设置多个属性的动画;
在多属性设置动画时,它比上面的ObjectAnimator更加酷炫、高效,因管理多个属性的invalidate方法统一调度、运行、触发,而不像上面分别调用,所以还会有一些性能优化。

myView.animate().x(0f).y(100f).start();

myView.animate() // need API12 
      .alpha(0)
      .y(mScreenHeight / 2)
      .setDuration(1000)    
      .withStartAction(new Runnable() {  // need API 12 
          @Override
          public void run() { 
             Log.e(TAG, "START"); 
          } 
      })
      .withEndAction(new Runnable() {  // need API 16 
          @Override
          public void run()  { 
             Log.e(TAG, "END"); 
             runOnUiThread(new Runnable() { 
                @Override
                public void run() { 
                   myView.setY(0); 
                   myView.setAlpha(1.0f); 
                } 
             }); 
          } 
       }).start(); 

LayoutAnimation LayoutTransition布局动画
LayoutAnimation
LayoutAnimation它是用来控制ViewGroup中所有的child view显示的动画,使用方式: xml定义使用, 代码定义方式
1、
a:LayoutAnimation动画直接在xml中定义(res/anim/customer_anim.xml):
//res/anim/slide_right.xml

<set xmlns:android="http://schemas.android.com/apk/res/android"   
        android:interpolator="@android:anim/accelerate_interpolator">  
    <translate android:fromXDelta="-100%p" android:toXDelta="0"  
            android:duration="@android:integer/config_shortAnimTime" />  
</set>

//res/animator/layout_anim.xml

<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"  
    android:delay="30%"   //动画播放的延时,可以是百分比,也可以是float小数,其中delay的单位为秒
    android:animationOrder="reverse"  //动画的播放顺序,有三个取值normal(0,顺序)、reverse(1,反序)、random(2,随机)
    android:animation="@anim/slide_right"/> //指向子控件所要播放的动画(表示孩子显示时的具体动画)

b:在ViewGroup的layout xml文件中设置:

<ListView...
    android:layoutAnimation="@animator/layout_anim"/>

2、代码中使用:
//ScaleAnimation sa = new ScaleAnimation(0, 1, 0, 1);
//sa.setDuration(2000);
//LayoutAnimationController controller = new LayoutAnimationController(sa, 0.5f); //设置布局动画的显示
//LayoutAnimationController 的第一个参数,是需要作用的动画,而第二个参数,则是每个子View显示的delay时间

Animation animation = AnimationUtils.loadAnimation(this, R.anim.slide_right);   //得到一个LayoutAnimationController对象; 

//LayoutAnimationController可实现一个界面中的多个控件按照相同的动画方式但是每个控件完成该动画的时刻不同

LayoutAnimationController controller = new LayoutAnimationController(animation);   //设置控件显示的顺序;  
controller.setOrder(LayoutAnimationController.ORDER_REVERSE);   //设置控件显示间隔时间;  
controller.setDelay(0.3);   //为ListView设置LayoutAnimationController属性;  
listView.setLayoutAnimation(controller);  
listView.startLayoutAnimation();  

public static final int ORDER_NORMAL = 0; //顺序 
public static final int ORDER_REVERSE = 1; //反序 
public static final int ORDER_RANDOM = 2; //随机 

LayoutTransition
LayoutTransition是从API Level 11出现的。LayoutTransition的动画效果只有当ViewGroup中有View添加、删除、隐藏、显示的时候才会体现出来。
它也有两种使用方式: xml定义使用, 代码定义方式
1、xml中使用系统默认的LayoutTransition动画:

<LinearLayout android:id="@+id/container"
    android:animateLayoutChanges="true"
    ...
/> 

在ViewGroup添加如上xml属性默认是没有任何动画效果的,当设置如上属性,然后调用ViewGroup的addView、removeView方法时就能看见系统默认的动画效果(即ViewGroup内部东东发生改变时才有效)。

mContainer.addView(newView, 0);

2、代码中使用LayoutTransition动画:
LayoutTransition类中主要的五种容器转换动画类型,具体如下:
LayoutTransition.APPEARING — 当一个View在ViewGroup中出现时,对此View设置的动画
LayoutTransition.CHANGE_APPEARING — 当一个View在ViewGroup中出现时,对此View对其他View位置造成影响,对其他View设置的动画
LayoutTransition.DISAPPEARING — 当一个View在ViewGroup中消失时,对此View设置的动画
LayoutTransition.CHANGE_DISAPPEARING — 当一个View在ViewGroup中消失时,对此View对其他View位置造成影响,对其他View设置的动画
LayoutTransition.CHANGE — 不是由于View出现或消失造成对其他View位置造成影响,然后对其他View设置的动画
注意:
动画到底设置在谁身上,此View还是其他View

代码中使用系统默认的LayoutTransition动画

LayoutTransition mTransitioner = new LayoutTransition();  
mViewGroup.setLayoutTransition(mTransitioner);  

动画使用示例:

private void setupCustomAnimations() {  
    LayoutTransition mTransitioner = new LayoutTransition(); 
    // 动画: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));  

    //通过使用LayoutTransition的方法setAnimator(),传入一个Animator和一个LayoutTransition类中定义的五种容器转换动画类型之一,来定制用于ViewGroup的动画       
    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);  
        }  
    });  

    mViewGroup.setLayoutTransition(mTransitioner);  

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值