您的位置:首页 > 移动开发 > Android开发

Android动画浅析

2015-12-10 00:39 411 查看
Android提供了3种动画类型:View Animation 、Drawable Animation 、Property Animation

  Drawable Animations就是很多书籍中提到的逐帧动画(frame-by-frame animation)

  View Animation有两个缺点:(1)View Animation一般只能修改组件(View Object)的部分属性,比如:scaling(大小)和rotation(旋转),但是无法修改组件的背景颜色。(2)View Animation使某个组件产生动画效果移动一段距离后,比如从屏幕左侧移动到右侧,其实整个过程是绘制出来的效果,该组件真正的位置依然保留在左侧,只有点击左侧位置才能触发该组件。所以想真正移动某组件,需要在动画结束后添加代码实现。

  Property Animation则没有以上View Animation的两个限制,Property Animation可以修改任何对象(View Object 或者 non-view Object)的任何属性,比如大小,旋转,颜色。并且,移动后的组件,位置也回跟随着改变。
[b]1.Drawable Animation[/b]

  定义动画的每个图片,定义在xml文件里面:

public class MainActivity extends Activity implements OnClickListener{

private Button scale;
private Button alpha;
private Button rotation;
private Button translate;
private Button animationSet;
// Alpha动画 - 渐变透明度
private Animation alphaAnimation = null;

// Sacle动画 - 渐变尺寸缩放
private Animation scaleAnimation = null;

// Translate动画 - 位置移动
private Animation translateAnimation = null;

// Rotate动画 - 画面旋转
private Animation rotateAnimation = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
// 将该逐帧xml文件设置为ImageView的背景
scale = (Button) findViewById(R.id.bt0);
scale.setOnClickListener(this);
alpha = (Button) findViewById(R.id.bt1);
alpha.setOnClickListener(this);
rotation = (Button) findViewById(R.id.bt2);
rotation.setOnClickListener(this);
translate = (Button) findViewById(R.id.bt3);
translate.setOnClickListener(this);
animationSet = (Button) findViewById(R.id.bt4);
animationSet.setOnClickListener(this);
}

@Override
public void onClick(View v) {
switch(v.getId()){
case R.id.bt0:  //缩放
scaleAnimation = new ScaleAnimation(0.1f, 1f, 0.1f, 1f,RotateAnimation.RELATIVE_TO_SELF,0.5f,RotateAnimation.RELATIVE_TO_SELF,0.5f);
scaleAnimation.setDuration(500);
scaleAnimation.setRepeatCount(Animation.INFINITE);
v.startAnimation(scaleAnimation);
break;
case R.id.bt1:   //透明
alphaAnimation = new AlphaAnimation(0.1f, 1.0f);
alphaAnimation.setDuration(3000);
v.startAnimation(alphaAnimation);
alphaAnimation.setRepeatCount(Animation.INFINITE);
break;
case R.id.bt2:   //旋转
rotateAnimation = new RotateAnimation(0f, 360f,RotateAnimation.RELATIVE_TO_SELF,0.5f,RotateAnimation.RELATIVE_TO_SELF,0.5f);
rotateAnimation.setDuration(1000);
v.startAnimation(rotateAnimation);
rotateAnimation.setRepeatCount(Animation.INFINITE);
break;
case R.id.bt3:   //平移
translateAnimation = new TranslateAnimation(0.1f, 100.0f,0.1f,100.0f);
translateAnimation.setDuration(1000);
v.startAnimation(translateAnimation);
translateAnimation.setRepeatCount(Animation.INFINITE);
break;
case R.id.bt4:  //动画集
translateAnimation = new TranslateAnimation(0.1f, 100.0f,0.1f,100.0f);
alphaAnimation = new AlphaAnimation(0.1f, 1.0f);
rotateAnimation = new RotateAnimation(0f, 360f);
AnimationSet set = new AnimationSet(true);
set.addAnimation(translateAnimation);
set.addAnimation(rotateAnimation);
set.addAnimation(alphaAnimation);
set.setDuration(1000);
v.startAnimation(set);
break;
}
}

}


View Code



2.3xml代码中定义animation

以scale为例,其他类似

scale标签是缩放动画,可以实现动态调控件尺寸的效果,有下面几个属性:

android:fromXScale 起始的X方向上相对自身的缩放比例,浮点值,比如1.0代表自身无变化,0.5代表起始时缩小一倍,2.0代表放大一倍;

android:toXScale 结尾的X方向上相对自身的缩放比例,浮点值;

android:fromYScale 起始的Y方向上相对自身的缩放比例,浮点值,

android:toYScale 结尾的Y方向上相对自身的缩放比例,浮点值;

android:pivotX 缩放起点X轴坐标,可以是数值、百分数、百分数p 三种样式,比如 50、50%、50%p,当为数值时,表示在当前View的左上角,即原点处加上50px,做为起始缩放点;如果是50%,表示在当前控件的左上角加上自己宽度的50%做为起始点;如果是50%p,那么就是表示在当前的左上角加上父控件宽度的50%做为起始点x轴坐标。(具体意义,后面会举例演示)

android:pivotY 缩放起点Y轴坐标,取值及意义跟android:pivotX一样。

从Animation类继承的属性:

android:duration 动画持续时间,以毫秒为单位

android:fillAfter 如果设置为true,控件动画结束时,将保持动画最后时的状态

android:fillBefore 如果设置为true,控件动画结束时,还原到开始动画前的状态

android:fillEnabled 与android:fillBefore 效果相同,都是在动画结束时,将控件还原到初始化状态

android:repeatCount 重复次数

android:repeatMode 重复类型,有reverse和restart两个值,reverse表示倒序回放,restart表示重新放一遍,必须与repeatCount一起使用才能看到效果。因为这里的意义是重复的类型,即回放时的动作。

android:interpolator 设定插值器,其实就是指定的动作效果,比如弹跳效果等,不在这小节中讲解,后面会单独列出一单讲解。

<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
android:fromXScale="0.0"
android:toXScale="1.4"
android:fromYScale="0.0"
android:toYScale="1.4"
android:pivotX="50"
android:pivotY="50"
android:duration="700" />


<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:duration="3000"
android:fillAfter="true">

<alpha
android:fromAlpha="0.0"
android:toAlpha="1.0"/>

<scale
android:fromXScale="0.0"
android:toXScale="1.4"
android:fromYScale="0.0"
android:toYScale="1.4"
android:pivotX="50%"
android:pivotY="50%"/>

<rotate
android:fromDegrees="0"
android:toDegrees="720"
android:pivotX="50%"
android:pivotY="50%"/>

</set>


在java代码中调用:

scaleAnimation = AnimationUtils.loadAnimation(this, R.anim.scaleanim);

[b]2.4Interpolator插值器[/b]



定义动画速率

AccelerateDecelerateInterpolator 在动画开始与介绍的地方速率改变比较慢,在中间的时候加速

AccelerateInterpolator 在动画开始的地方速率改变比较慢,然后开始加速

AnticipateInterpolator 开始的时候向后然后向前甩

AnticipateOvershootInterpolator 开始的时候向后然后向前甩一定值后返回最后的值

BounceInterpolator 动画结束的时候弹起

CycleInterpolator 动画循环播放特定的次数,速率改变沿着正弦曲线

DecelerateInterpolator 在动画开始的地方快然后慢

LinearInterpolator 以常量速率改变

OvershootInterpolator 向前甩一定值后再回到原来位置

2.5 通过AnimationSet应用多个动画

  AnimationSet类是Android系统中的动画集合类,用于控制View对象进行多个动作的组合,该类继承于Animation类。AnimationSet类中的很多方法都与Animation类一致,该类中最常用的方法便是addAnimation方法,该方法用于为动画集合对象添加动画对象。

AnimationSet set=new AnimationSet(true);    //创建动画集对象
set.addAnimation(translateAnimation);       //添加位置变化动画
set.addAnimation(scaleAnimation);           //添加尺寸变化动画
set.addAnimation(alphaAnimation);           //添加透明度渐变动画
set.setFillAfter(true);                 //停留在最后的位置
set.setFillEnabled(true);
image.setAnimation(set);                    //设置动画
set.startNow();                         //启动动画


[b]3.Property Animation[/b]

  属性动画,它更改的是对象的实际属性,在View Animation(Tween Animation)中,其改变的是View的绘制效果,真正的View的属性保持不变,比如无论你在对话中如何缩放Button的大小,Button的有效点击区域还是没有应用动画时的区域,其位置与大小都不变。而在Property Animation中,改变的是对象的实际属性,如Button的缩放,Button的位置与大小属性值都改变了。而且Property Animation不止可以应用于View,还可以应用于任何对象。Property Animation只是表示一个值在一段时间内的改变,当值改变时要做什么事情完全是你自己决定的。

在Property Animation中,可以对动画应用以下属性:

Duration:动画的持续时间

TimeInterpolation:属性值的计算方式,如先快后慢

TypeEvaluator:根据属性的开始、结束值与TimeInterpolation计算出的因子计算出当前时间的属性值

Repeat Count and behavoir:重复次数与方式,如播放3次、5次、无限循环,可以此动画一直重复,或播放完时再反向播放

Animation sets:动画集合,即可以同时对一个对象应用几个动画,这些动画可以同时播放也可以对不同动画设置不同开始偏移

Frame refreash delay:多少时间刷新一次,即每隔多少时间计算一次属性值,默认为10ms,最终刷新时间还受系统进程调度与硬件的影响

3.1类图



  ObjectAnimator 动画的执行类,后面详细介绍

  ValueAnimator 动画的执行类,后面详细介绍

  AnimatorSet 用于控制一组动画的执行:线性,一起,每个动画的先后执行等。

  AnimatorInflater 用户加载属性动画的xml文件

  TypeEvaluator 类型估值,主要用于设置动画操作属性的值。

  TimeInterpolator 时间插值,上面已经介绍。

  总的来说,属性动画就是,动画的执行类来设置动画操作的对象的属性、持续时间,开始和结束的属性值,时间差值等,然后系统会根据设置的参数动态的变化对象的属性。

3.2 ObjectAnimator

  1、提供了ofInt、ofFloat、ofObject,这几个方法都是设置动画作用的元素、作用的属性、动画开始、结束、以及中间的任意个属性值。

  当对于属性值,只设置一个的时候,会认为当前对象该属性的值为开始(getPropName反射获取),然后设置的值为终点。如果设置两个,则一个为开始、一个为结束~~~

动画更新的过程中,会不断调用setPropName更新元素的属性,所有使用ObjectAnimator更新某个属性,必须得有getter(设置一个属性值的时候)和setter方法~

  2、如果你操作对象的该属性方法里面,比如上例的setRotationX如果内部没有调用view的重绘,则你需要自己按照下面方式手动调用。

anim.addUpdateListener(new AnimatorUpdateListener()
{
@Override
public void onAnimationUpdate(ValueAnimator animation)
{
//                view.postInvalidate();
//                view.invalidate();
}
});


直接上例子:

package com.example.drawableanimationdemo;

import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.app.Activity;
import android.graphics.drawable.AnimationDrawable;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.Window;
import android.view.animation.*;
import android.widget.Button;
import android.widget.ImageView;

public class MainActivity extends Activity implements OnClickListener {

private Button scale;
private Button rotation;
private Button translate;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
scale = (Button) findViewById(R.id.bt0);
scale.setOnClickListener(this);

rotation = (Button) findViewById(R.id.bt2);
rotation.setOnClickListener(this);
translate = (Button) findViewById(R.id.bt1);
translate.setOnClickListener(this);
}

@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt0: // 缩放
ObjectAnimator o = ObjectAnimator.ofFloat(v, "scaleX", 0.1f, 1.0f);
o.setRepeatCount(5);
o.setDuration(3000);
o.start();
break;
case R.id.bt2: // 旋转
PropertyValuesHolder p1 = PropertyValuesHolder.ofFloat("alpha",
0.1f, 0.9f);
PropertyValuesHolder p2 = PropertyValuesHolder.ofFloat("rotation",
0, 360);
PropertyValuesHolder p4 = PropertyValuesHolder.ofFloat("scaleX",
0, 1);
PropertyValuesHolder p5 = PropertyValuesHolder.ofFloat("scaleY",
0, 1);
ObjectAnimator o1 = ObjectAnimator
.ofPropertyValuesHolder(v, p1, p2,p4,p5);
o1.setRepeatCount(5);
o1.setDuration(5000).start();
break;
case R.id.bt1: // 平移
ObjectAnimator o2 = ObjectAnimator.ofFloat(v, "translationX", 20f,
300f);
o2.setRepeatCount(5);
o2.setRepeatMode(ObjectAnimator.REVERSE);
o2.setDuration(3000);
o2.setInterpolator(new BounceInterpolator());
o2.start();
break;
}
}
}


其中用到了PropertyValuesHolder类,用作组合设计。

[b]3.3 ValueAnimator[/b]

  ValueAnimator包含Property Animation动画的所有核心功能,如动画时间,开始、结束属性值,相应时间属性值计算方法等。应用Property Animation有两个步聚:

计算属性值

根据属性值执行相应的动作,如改变对象的某一属性。

  ValuAnimiator只完成了第一步工作,如果要完成第二步,需要实现ValueAnimator.onUpdateListener接口,这个接口只有一个函数onAnimationUpdate(),在这个函数中会传入ValueAnimator对象做为参数,通过这个ValueAnimator对象的getAnimatedValue()函数可以得到当前的属性值如:

ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);
animation.setDuration(1000);
animation.addUpdateListener(new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
Log.i("update", ((Float) animation.getAnimatedValue()).toString());//在这里改变对象的属性
   invalidate(); //刷新对象的属性,否则不会调用重新绘制
}
});
animation.setInterpolator(new CycleInterpolator(3));
animation.start();


3.4 监听器

Animator.AnimatorListener:

onAnimationStart()
onAnimationEnd()
onAnimationRepeat()
//当动画被取消时调用,同时会调用onAnimationEnd().
onAnimationCancel()


ValueAnimator.AnimatorUpdateListener

onAnimationUpdate()  //通过监听这个事件在属性的值更新时执行相应的操作,对于ValueAnimator一般要监听此事件执行相应的动作,不然Animation没意义,在ObjectAnimator(继承自ValueAnimator)中会自动更新属性,如无必要不必监听。在函数中会传递一个ValueAnimator参数,通过此参数的getAnimatedValue()取得当前动画属性值。


AnimatorListenerAdapter

  AnimatorListenerAdapter继承了AnimatorListener接口,然后空实现了所有的方法。可以继承AnimatorListenerAdapter而不是实现AnimatorListener接口来简化操作,这样我们就只用定义想监听的事件而不用实现每个函数却只定义一空函数体。

ObjectAnimator oa=ObjectAnimator.ofFloat(tv, "alpha", 0f, 1f);
oa.setDuration(3000);
oa.addListener(new AnimatorListenerAdapter(){
public void on AnimationEnd(Animator animation){
Log.i("Animation","end");
}
});
oa.start();


[b]3.5 通过AnimatorSet应用多个动画[/b]

  AnimatorSet提供了一个把多个动画组合成一个组合的机制,并可设置组中动画的时序关系,如同时播放,顺序播放等。我们最常用的是调用其play、before、with、after 等方法设置动画的执行顺序。

//使用playTogether两个动画同时执行,当然还有playSequentially依次执行~~
void  playSequentially(Animator... items)
void  playSequentially(List<Animator> items)
void  playTogether(Collection<Animator> items)
void  playTogether(Animator... items)


AnimatorSet bouncer = new AnimatorSet();
bouncer.play(anim1).before(anim2);
bouncer.play(anim2).with(anim3);
bouncer.play(anim2).with(anim4)
bouncer.play(anim5).after(amin2);
animatorSet.start();


[b]3.5 TimeInterplator[/b]

Time interplator定义了属性值变化的方式,如线性均匀改变,开始慢然后逐渐快等。在Property Animation中是TimeInterplator,在View Animation中是Interplator,这两个是一样的。Interplator继承自TimeInterplator,内部没有任何其他代码。

AccelerateInterpolator      加速,开始时慢中间加速

DecelerateInterpolator       减速,开始时快然后减速

AccelerateDecelerateInterolator  先加速后减速,开始结束时慢,中间加速

AnticipateInterpolator       反向 ,先向相反方向改变一段再加速播放

AnticipateOvershootInterpolator  反向加回弹,先向相反方向改变,再加速播放,会超出目的值然后缓慢移动至目的值

BounceInterpolator        跳跃,快到目的值时值会跳跃,如目的值100,后面的值可能依次为85,77,70,80,90,100

CycleIinterpolator         循环,动画循环一定次数,值的改变为一正弦函数:Math.sin(2 * mCycles * Math.PI * input)

LinearInterpolator         线性,线性均匀改变

OvershottInterpolator       回弹,最后超出目的值然后缓慢改变到目的值

TimeInterpolator         一个接口,允许你自定义interpolator,以上几个都是实现了这个接口

3.6综合示例

/*
* Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0 *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.example.android.apis.animation;

// Need the following import to get access to the app resources, since this
// class is in a sub-package.
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.widget.LinearLayout;
import com.example.android.apis.R;

import android.animation.AnimatorListenerAdapter;
import android.animation.Keyframe;
import android.animation.LayoutTransition;
import android.animation.PropertyValuesHolder;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.CompoundButton;

import android.app.Activity;
import android.os.Bundle;
import android.widget.Button;

/**
* This application demonstrates how to use LayoutTransition to automate transition animations
* as items are hidden or shown in a container.
*/
public class LayoutAnimationsHideShow extends Activity {

private int numButtons = 1;
ViewGroup container = null;
private LayoutTransition mTransitioner;//定义ViewGroup组件变化时的动画

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_animations_hideshow);

final CheckBox hideGoneCB = (CheckBox) findViewById(R.id.hideGoneCB);

container = new LinearLayout(this);
container.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT));

// Add a slew of buttons to the container. We won't add any more buttons at runtime, but
// will just show/hide the buttons we've already created
for (int i = 0; i < 4; ++i) {
Button newButton = new Button(this);
newButton.setText(String.valueOf(i));
container.addView(newButton);
newButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
v.setVisibility(hideGoneCB.isChecked() ? View.GONE : View.INVISIBLE);
}
});
}

resetTransition();   //使用默认的LayoutTransition

ViewGroup parent = (ViewGroup) findViewById(R.id.parent);
parent.addView(container);  //将4个button对应的ViewGroup添加到主布局中

Button addButton = (Button) findViewById(R.id.addNewButton);
addButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
for (int i = 0; i < container.getChildCount(); ++i) {
View view = (View) container.getChildAt(i);
view.setVisibility(View.VISIBLE);//显示4个button
}
}
});

CheckBox customAnimCB = (CheckBox) findViewById(R.id.customAnimCB);
customAnimCB.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
long duration;
if (isChecked) {              //使用自定义LayoutTransition
mTransitioner.setStagger(LayoutTransition.CHANGE_APPEARING, 30);
mTransitioner.setStagger(LayoutTransition.CHANGE_DISAPPEARING, 30);
setupCustomAnimations();
duration = 500;
} else {                      //使用默认LayoutTransition
resetTransition();
duration = 300;
}
mTransitioner.setDuration(duration);
}
});
}

private void resetTransition() {
mTransitioner = new LayoutTransition();
container.setLayoutTransition(mTransitioner);
}

private void setupCustomAnimations() {
// 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);//设置组件CHANGE_APPEARING动画
changeIn.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator anim) {
View view = (View) ((ObjectAnimator) anim).getTarget();
view.setScaleX(1f);
view.setScaleY(1f);
}
});

// 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));//设置组件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);
}
});

// Adding
ObjectAnimator animIn = ObjectAnimator.ofFloat(null, "rotationY", 90f, 0f).
setDuration(mTransitioner.getDuration(LayoutTransition.APPEARING));
mTransitioner.setAnimator(LayoutTransition.APPEARING, animIn);//设置组件APPEARING动画
animIn.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator anim) {
View view = (View) ((ObjectAnimator) anim).getTarget();
view.setRotationY(0f);
}
});

// Removing
ObjectAnimator animOut = ObjectAnimator.ofFloat(null, "rotationX", 0f, 90f).
setDuration(mTransitioner.getDuration(LayoutTransition.DISAPPEARING));
mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);//设置组件DISAPPEARING动画
animOut.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator anim) {
View view = (View) ((ObjectAnimator) anim).getTarget();
view.setRotationX(0f);
}
});

}
}


  这个是官方apiDemo源码,解释下其中代码:

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            - 对出现的view设置
  CHANGE_APPEARING       - 当出现的view时,对其他受影响view设置
  DISAPPEARING          - 对消失的view设置
  CHANGE_DISAPPEARING     - 当消失view时,对其他受影响view设置

  你可以自己定义这四种事件类型的动画,也可以使用默认的动画。最后通过setLayoutTransition(LayoutTransition)方法把这些动画以一个 LayoutTransition 对象的形式设置给一个ViewGroup即可。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: