欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

[Android][Animation]

程序员文章站 2022-03-01 20:51:57
...

1.View Animation(Tweened Animation)补间动画

View Animation主要是针对View的,而且它只是让View展示指定动画,但是并不会改变View的属性。也就是说使用tweened动画来实现移动,缩放,旋转,透明度,最后都是没有改变view的位置,大小,角度,透明度,我们看到的只是一个动画效果。

1).创建动画对象

(1)直接new

Android提供了四个类TranslateAnimation,ScaleAnimation,RotateAnimation和AlphaAnimation。我们可以通过这四个类实现移动,缩放,旋转和透明度设置。如果一个View要同时执行多个动画可以使用AnimationSet。
例子一:TranslateAnimation

    /**
     * 确实如果使用TranslateAnimation实现位移动画,如果没有setX,setY,那么view是不会移动到指定位置的,
     * 而且通过setX,setY移动view到知道位置的时候,view是会闪一下,如果使用tweened动画来实现缩放,旋转,透明度,最后都是没有改变view的,我们看到的只是一个动画效果
     */
    private void transition() {
        UiUtil.initialize(this);
        animation = new TranslateAnimation(0, UiUtil.getScreenWidth() / 2, 0,
                UiUtil.getScreenHeight() / 2);
        animation.setDuration(2000);
        animation.setAnimationListener(new AnimationListener() {

            @Override
            public void onAnimationStart(Animation animation) {
                Log.i("lgy",
                        "start----x:" + button.getX() + " y:" + button.getY());
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                button.setX(UiUtil.getScreenWidth() / 2);
                button.setY(UiUtil.getScreenHeight() / 2);
                Log.i("lgy",
                        "end----x:" + button.getX() + " y:" + button.getY());
            }
        });
        button.startAnimation(animation);
    }

例子二:ScaleAnimation

    /**
     * float fromX 动画起始时 X坐标上的伸缩尺寸 
     * float toX 动画结束时 X坐标上的伸缩尺寸 
     * float fromY 动画起始时Y坐标上的伸缩尺寸 
     * float toY 动画结束时Y坐标上的伸缩尺寸 
     * int pivotXType 动画在X轴相对于控件位置类型 
     * float pivotXValue 动画相对于控件的X坐标的开始位置 
     * int pivotYType 动画在Y轴相对于控件位置类型 
     * float pivotYValue 动画相对于控件的Y坐标的开始位置
     * 1.四个参数的ScaleAnimation默认是动画是从左上角开始,
     * 所以new ScaleAnimation(0.0f, 1.4f, 0.0f, 1.4f),
     * 你会看到的效果是动画会以view的左上角为定点,开始向x轴和y轴慢慢伸长到1.4倍,
     * 动画结束后,由于tweened动画不改变view的属性,view就会恢复为正常状态
     * 2.八个参数的ScaleAnimation可以定义相对于控件位置类型 
     * (1)RELATIVE_TO_SELF 相对于自己
     * (2)RELATIVE_TO_PARENT 相对于父控件
     * (3)ABSOLUTE 绝对位置 ,例如Animation.ABSOLUTE, new ScaleAnimation(0.0f, 1.4f, 0.0f, 1.4f, 
                Animation.ABSOLUTE, 200f, Animation.ABSOLUTE, 100f)意思是相对于当前位置
                x轴增量为200的坐标点,y轴增量为100的坐标点
            如果使用的是RELATIVE_TO_SELF,RELATIVE_TO_PARENT类型,那么他的参数表示的的是倍数
            如果使用的是ABSOLUTE,那么他表示的就是具体的增量
     * 
     */
    private void scale() {
        UiUtil.initialize(this);
//      scaleAnimation = new ScaleAnimation(0.0f, 1.4f, 0.0f, 1.4f);
//      scaleAnimation = new ScaleAnimation(0.0f, 1.4f, 0.0f, 1.4f, 
//              Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
        scaleAnimation = new ScaleAnimation(0.0f, 1.4f, 0.0f, 1.4f, 
                Animation.RELATIVE_TO_SELF, 1f, Animation.RELATIVE_TO_SELF, 1f);
        scaleAnimation.setDuration(2000);
        scaleAnimation.setAnimationListener(new AnimationListener() {

            @Override
            public void onAnimationStart(Animation animation) {
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onAnimationEnd(Animation animation) {
            }
        });
        button.startAnimation(scaleAnimation);
    }

例子三:RotateAnimation

    /**
     * float fromDegrees:旋转的开始角度。 
     * float toDegrees:旋转的结束角度。 
     * int pivotXType:X轴上旋转点模式,可以取值为ABSOLUTE、RELATIVE_TO_SELF、RELATIVE_TO_PARENT。 
     * float pivotXValue:X轴上旋转点的值。
     * int pivotYType:Y轴上旋转点模式,可以取值为ABSOLUTE、RELATIVE_TO_SELF、RELATIVE_TO_PARENT。 
     * float pivotYValue:Y轴上旋转点的值。
     */
    private void rotate() {
        UiUtil.initialize(this);
        rotateAnimation = new RotateAnimation(0f,360f,Animation.RELATIVE_TO_SELF, 
                0.5f,Animation.RELATIVE_TO_SELF,0.5f); 
        rotateAnimation.setDuration(2000);
        rotateAnimation.setAnimationListener(new AnimationListener() {

            @Override
            public void onAnimationStart(Animation animation) {
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onAnimationEnd(Animation animation) {
            }
        });
        button.startAnimation(rotateAnimation);
    }

例子四:AlphaAnimation

    /**
     * float fromAlpha:开始时候的透明度。 
     * float toAlpha:结束时候的透明度。 
     * 这里都是用倍数表示
     */
    private void alpha() {
        UiUtil.initialize(this);
        alphaAnimation = new AlphaAnimation(0f, 1f); 
        alphaAnimation.setDuration(2000);
        alphaAnimation.setAnimationListener(new AnimationListener() {

            @Override
            public void onAnimationStart(Animation animation) {
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onAnimationEnd(Animation animation) {
            }
        });
        button.startAnimation(alphaAnimation);
    }

例子五:AnimationSet

    /**
     * 同时执行多个动画
     */
    private void animSet() {
        UiUtil.initialize(this);
        animationSet = new AnimationSet(true);
        alphaAnimation = new AlphaAnimation(0f, 1f); 
        animationSet.addAnimation(alphaAnimation);
        rotateAnimation = new RotateAnimation(0f,360f,Animation.RELATIVE_TO_SELF, 
                0.5f,Animation.RELATIVE_TO_SELF,0.5f); 
        animationSet.addAnimation(rotateAnimation);
        scaleAnimation = new ScaleAnimation(0.0f, 1.4f, 0.0f, 1.4f, 
                Animation.RELATIVE_TO_SELF, 1f, Animation.RELATIVE_TO_SELF, 1f);
        animationSet.addAnimation(scaleAnimation);
        animation = new TranslateAnimation(0, UiUtil.getScreenWidth() / 2, 0,
                UiUtil.getScreenHeight() / 2);
        animationSet.addAnimation(animation);
        animationSet.setDuration(2000);
        button.startAnimation(animationSet);
    }

(2)AnimationUtils.loadAnimation

也就是通过加载定义好的xml文件来实例化动画对象。
步骤一:在res文件夹下新建一个anim文件夹(anim文件夹下放的是Tweened动画,如果想放Property动画,必须要在res下新建一个animator,把Property动画的文件放里边,在Android Studio里是需要这样区分的,Eclipse没有验证,就不清楚了)
步骤二:在anim里可以定义自己Tweened动画xml文件,他们一般是以set为根标签。

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

    <translate
        android:fromXDelta="-100%"
        android:toXDelta="0%"
        android:duration="1000" />
</set>

步骤三:加载xml,实例化动画对象

    /**
     * 这里是实现将mContentView从左边移动出现,而mLoadingView向左移动消失的效果
     */
    private void xmlAnim() {
        contentViewAnim = AnimationUtils.loadAnimation(this, R.anim.tweened_anim_translation);
        contentViewAnim.setAnimationListener(new AnimationListener() {

            @Override
            public void onAnimationStart(Animation animation) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onAnimationRepeat(Animation animation) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                mContentView.setVisibility(View.VISIBLE);
            }
        });
        mContentView.startAnimation(contentViewAnim);
        loadingViewAnim = AnimationUtils.loadAnimation(this, R.anim.tweened_anim_translation2);
        loadingViewAnim.setAnimationListener(new AnimationListener() {

            @Override
            public void onAnimationStart(Animation animation) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onAnimationRepeat(Animation animation) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                mLoadingView.setVisibility(View.GONE);
            }
        });
        mLoadingView.startAnimation(loadingViewAnim);
    }

2).动画监听setAnimationListener

我们可以对动画的行为进行监听,根据需要执行我们的操作,AnimationListener这个接口可以监听到动画开始,重复,动画结束的动作。

loadingViewAnim.setAnimationListener(new AnimationListener() {

            @Override
            public void onAnimationStart(Animation animation) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onAnimationRepeat(Animation animation) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                mLoadingView.setVisibility(View.GONE);
            }
        });

3).插值器Imterpolator

其实插值器就是设置动画改变的速率。
* 1:AccelerateDecelerateInterpolator 加速减速插补器(先慢后快再慢)
* 2:AccelerateInterpolator 加速插补器(先慢后快)
* 3:AnticipateInterpolator 向前插补器(先往回跑一点,再加速向前跑)
* 4:AnticipateOvershootInterpolator 向前向后插补器(先往回跑一点,再向后跑一点,再回到终点)
* 5:BounceInterpolator 反弹插补器(在动画结束的时候回弹几下,如果是竖直向下运动的话,就是玻璃球下掉弹几下的效果)
* 6:CycleInterpolator 循环插补器(按指定的路径以指定时间(或者是偏移量)的1/4、变速地执行一遍,再按指定的轨迹的相反反向走1/2的时间,再按指定的路径方向走完剩余的1/4的时间,最后回到原点。假如:默认是让a从原点往东跑100米。它会先往东跑100米,然后往西跑200米,再往东跑100米回到原点。可在代码中指定循环的次数)
* 7:DecelerateInterpolator 减速插补器(先快后慢)
* 8:LinearInterpolator 直线插补器(匀速)
* 9:OvershootInterpolator 超出插补器(向前跑直到越界一点后,再往回跑)
* 10:FastOutLinearInInterpolator MaterialDesign基于贝塞尔曲线的插补器 效果:依次 慢慢快
* 11:FastOutSlowInInterpolator MaterialDesign基于贝塞尔曲线的插补器 效果:依次 慢快慢
* 12:LinearOutSlowInInterpolator MaterialDesign基于贝塞尔曲线的插补器 效果:依次 快慢慢

setInterpolator(new LinearOutSlowInInterpolator())

4).改变属性

我们知道Tweened动画只是让View展示指定动画,但是并不会改变View的属性。那么如果我们要改变它的属性可以通过View的set方法

    /**
     * 确实如果使用TranslateAnimation实现位移动画,如果没有setX,setY,那么view是不会移动到指定位置的,
     * 而且通过setX,setY移动view到知道位置的时候,view是会闪一下,如果使用tweened动画来实现缩放,旋转,透明度,最后都是没有改变view的,我们看到的只是一个动画效果
     */
    private void transition() {
        UiUtil.initialize(this);
        animation = new TranslateAnimation(0, UiUtil.getScreenWidth() / 2, 0,
                UiUtil.getScreenHeight() / 2);
        animation.setDuration(2000);
        animation.setAnimationListener(new AnimationListener() {

            @Override
            public void onAnimationStart(Animation animation) {
                Log.i("lgy",
                        "start----x:" + button.getX() + " y:" + button.getY());
            }

            @Override
            public void onAnimationRepeat(Animation animation) {
                // TODO Auto-generated method stub

            }

            @Override
            public void onAnimationEnd(Animation animation) {
                button.setX(UiUtil.getScreenWidth() / 2);
                button.setY(UiUtil.getScreenHeight() / 2);
//              button.setAlpha(1f);
//              button.setScaleX(1.4f);
//              button.setScaleY(1.4f);
//              button.setRotationX(0);
//              button.setRotationY(100);
                Log.i("lgy",
                        "end----x:" + button.getX() + " y:" + button.getY());
            }
        });
        button.startAnimation(animation);
    }

2.Drawable Animation(帧动画)

这个其实就是按顺序一帧一帧的播放图片。

1)使用xml加载

步骤一:在res下的anim文件夹下创建帧动画xml文件,这个文件的根标签是animation-list。

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"  
    android:oneshot="false">  
    <item android:drawable="@drawable/little_gray_01" android:duration="300" />  
    <item android:drawable="@drawable/little_gray_03" android:duration="300" />  
    <item android:drawable="@drawable/little_gray_04" android:duration="300" />  
    <item android:drawable="@drawable/little_gray_05" android:duration="300" />  
</animation-list> 

步骤二:加载xml,创建对象

    /**
     * ProgressBar可以用下面这个设置
     *  bar.setIndeterminate(true);
        bar.setIndeterminateDrawable(getResources().getDrawable(R.anim.frame_anim_list));       
     */
    private void xmlAnimation()
    {
        imageView.setBackgroundResource(R.anim.frame_anim_list);
        AnimationDrawable animation = (AnimationDrawable) imageView.getBackground();
        animation.start();
    }

2)不使用xml

    private void noXmlAnimation()
    {
        AnimationDrawable anim = new AnimationDrawable();  
        Drawable drawable1 = getResources().getDrawable(R.drawable.little_gray_01); 
        Drawable drawable3 = getResources().getDrawable(R.drawable.little_gray_03); 
        Drawable drawable4 = getResources().getDrawable(R.drawable.little_gray_04); 
        Drawable drawable5 = getResources().getDrawable(R.drawable.little_gray_05); 

        anim.addFrame(drawable1, 300);
        anim.addFrame(drawable3, 300); 
        anim.addFrame(drawable4, 300); 
        anim.addFrame(drawable5, 300); 
        anim.setOneShot(false); 
        imageView.setBackground(anim);
        anim.start(); 
    }

3.Property Animation

是在Android 3.0中才引进的,它更改的是对象的实际属性,在View Animation(Tween Animation)中,其改变的是View的绘制效果,真正的View的属性保持不变。而且Property Animation不止可以应用于View,还可以应用于任何对象。Property Animation只是表示一个值在一段时间内的改变,当值改变时要做什么事情完全是你自己决定的。

1)ValueAnimator

ValueAnimator包含Property Animation动画的所有核心功能,它是PropertyAnimation动画的基础,ObjectAnimator也是继承了ValueAnimation。

(1)基础用法

这个例子只修改了view的一个属性:x的坐标

    /**
     * 只修改button的x轴动画
     */
    private void valueAnim()
    {
        UiUtil.initialize(this);
        ValueAnimator animator = ValueAnimator.ofFloat(0f,UiUtil.getScreenWidth()/2);
        animator.addUpdateListener(new AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                button.setTranslationX((Float)animation.getAnimatedValue());
            }
        });
        animator.setDuration(2000);
        animator.start();
    }
(2)修改多个属性

下面展示的是同时修改x坐标和y坐标的值,这里用到了PropertyValuesHolder ,可以使用它来同时执行多个动画。

    /**
     * 修改button的x轴和Y轴动画,通过下面的方法可以传多个动画
     */
    private void valueAnim2()
    {
        UiUtil.initialize(this);
        PropertyValuesHolder xvalue = PropertyValuesHolder.ofFloat("x", 0f,UiUtil.getScreenWidth()/2);
        PropertyValuesHolder yvalue = PropertyValuesHolder.ofFloat("y", 0f,UiUtil.getScreenHeight()/2);
        ValueAnimator animator = ValueAnimator.ofPropertyValuesHolder(xvalue,yvalue);
        animator.addUpdateListener(new AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                button.setTranslationX((Float)animation.getAnimatedValue("x"));
                button.setTranslationY((Float)animation.getAnimatedValue("y"));
            }
        });
        animator.setDuration(2000);
        animator.start();
    }
(3)监听属性的渐变值

可以通过addUpdateListener监听到属性的渐变值,可以看到下面的代码,
我们可以通过PropertyValuesHolder 的ofFloat给某个属性定义一个propertyName,然后在addUpdateListener里的回调方法onAnimationUpdate,可以通过animation.getAnimatedValue(propertyName)获取对于该属性名的渐变值。

    private void valueAnim2()
    {
        UiUtil.initialize(this);
        PropertyValuesHolder xvalue = PropertyValuesHolder.ofFloat("x", 0f,UiUtil.getScreenWidth()/2);
        PropertyValuesHolder yvalue = PropertyValuesHolder.ofFloat("y", 0f,UiUtil.getScreenHeight()/2);
        ValueAnimator animator = ValueAnimator.ofPropertyValuesHolder(xvalue,yvalue);
        animator.addUpdateListener(new AnimatorUpdateListener() {

            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                button.setTranslationX((Float)animation.getAnimatedValue("x"));
                button.setTranslationY((Float)animation.getAnimatedValue("y"));
            }
        });
        animator.setDuration(2000);
        animator.start();
    }

2)ObjectAnimator

(1)ObjectAnimator的基本用法

也是修改一个属性值。

    /**
     * 修改button的x轴动画
     */
    private void objectAnim()
    {
        UiUtil.initialize(this);
        ObjectAnimator animator = ObjectAnimator
                .ofFloat(button, "translationX", 0f,UiUtil.getScreenWidth()/2);
        animator.setDuration(2000);
        animator.start();
    }
(2)修改多个属性值
    /**
     * 修改button的x轴和Y轴动画,通过下面的方法可以传多个动画
     */
    private void objectAnim2()
    {
        UiUtil.initialize(this);
        PropertyValuesHolder xvalue = PropertyValuesHolder.ofFloat("x", 0f,UiUtil.getScreenWidth()/2);
        PropertyValuesHolder yvalue = PropertyValuesHolder.ofFloat("y", 0f,UiUtil.getScreenHeight()/2);
        ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(button, xvalue,yvalue);
        animator.setDuration(2000);
        animator.start();
    }
(3)加载xml方式执行动画

步骤一:在res的animator目录下创建动画xml文件,这动画很明显,是同时执行将view的x坐标和y坐标都移动到400处。

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="2000"
    android:ordering="together" >
 <!-- 动画执行顺序 sequentially:顺序执行;together:同时执行。 -->

    <objectAnimator
        android:propertyName="translationX"
        android:duration="2000"
        android:valueFrom="0"
        android:valueTo="400"
        android:valueType="floatType" />
    <objectAnimator
        android:propertyName="translationY"
        android:valueFrom="0"
        android:duration="2000"
        android:valueTo="400"
        android:valueType="floatType" />
 <!-- 动画值的类型 -->

</set>

步骤二:加载xml文件,执行动画
通过AnimatorInflater.loadAnimator方法可以获得一个Animator 对象。

    /**
     * 修改button的x轴和Y轴动画,通过下面的方法可以传多个动画
     */
    private void objectAnimByXml()
    {

        Animator animator = AnimatorInflater.loadAnimator(this, R.animator.property_tran_x);
        animator.setTarget(button);
        animator.start();
    }

3)AnimatorSet 和 PropertyValuesHolder

AnimatorSet 和PropertyValuesHolder都是可以执行多个动画的,PropertyValuesHolder的动画是必须全部同时执行的,而AnimatorSet 可以控制动画是同时执行还是先后执行。

    /**
     * AnimatorSet
     * play和with可以同时播放多个动画
     * play,after,before可以设置动画的先后顺序
     * 而PropertyValuesHolder是无法设置动画的先后播放顺序,只能同时执行多个动画
     */
    private void objectAnimSet()
    {
        UiUtil.initialize(this);
        ObjectAnimator animatorx = ObjectAnimator
                .ofFloat(button, "translationX", 0f,UiUtil.getScreenWidth()/2);
        ObjectAnimator animatory = ObjectAnimator
                .ofFloat(button, "translationY", 0f,UiUtil.getScreenHeight()/2);
        AnimatorSet animatorSet = new AnimatorSet();
        animatorSet.play(animatorx).with(animatory);
        animatorSet.setDuration(2000);
        animatorSet.start();
    }

4)ViewPropertyAnimator

ViewPropertyAnimator也是用于同时执行多个动画的,但是它可以直接从view的animate()方法里获得,如果是对view要执行多个动画的情况下,使用它是十分简便的。

    /**
     * ViewPropertyAnimator
     * 如果View只用到一两个动画,那么用ObjectAnimatior就好了,
     * 但是如果一个View同时要执行多个动画ViewPropertyAnimator的方法会更佳
     */
    private void ViewPropertyAnim()
    {
        UiUtil.initialize(this);
        button.animate()
        .translationX(UiUtil.getScreenWidth()/2)
        .translationY(UiUtil.getScreenHeight()/2)
        .setDuration(2000)
        .start();
    }

5)布局改变的动画(Viewgroup)

API 11后,在ViewGroup中添加或删除view会触发系统提供的布局动画。

(1)在xml代码中的ViewGroup中添加android:animateLayoutChanges=”true”既可触发系统内置的增加删除item view的动画效果。LinearLayout是继承ViewGroup的这个大家都知道的哦。
<?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:id="@+id/body"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:animateLayoutChanges="true"
        android:layout_weight="1"
        android:showDividers="middle"

        android:orientation="vertical" >
    </LinearLayout>

    <Button
        android:id="@+id/add"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:text="ADD" />

</LinearLayout>
2)代码中的ViewGroup直接设置setLayoutTransition(new LayoutTransition());即可调用系统提供的默认动画。
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test_linearlaout_anim);
        bodyLayout = (LinearLayout) findViewById(R.id.body);
        bodyLayout.setLayoutTransition(new LayoutTransition());
        add = (Button) findViewById(R.id.add);
        add.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {
                addItem();
            }
        });
    }
(3)自定义ViewGroup增加和删除item的动画

可以通过自己定义LayoutTransition,然后通过setLayoutTransition来设置自己定义的动画。

    /**
     * 自定义的LayoutTransaction是在API11出现的
     * ObjectAnimator outAnimator = new ObjectAnimator().ofFloat(null, "translationX", 0f,UiUtil.getScreenWidth()).setDuration(4000);
     * 上面这样在结尾设置setDuration(4000)动画时间是没有效果的
     * 需要在layoutTransition对象直接设置动画时间才有效果layoutTransition.setDuration(4000)
     */
    private LayoutTransition initCustomLayoutTransition()
    {
        UiUtil.initialize(this);
        LayoutTransition layoutTransition = new LayoutTransition();
        ObjectAnimator outAnimator = ObjectAnimator.ofFloat(null, "translationX", 0f,UiUtil.getScreenWidth()).setDuration(3000);
        layoutTransition.setAnimator(LayoutTransition.DISAPPEARING, outAnimator);
//      layoutTransition.setDuration(4000);
        ObjectAnimator intAnimator = ObjectAnimator.ofFloat(null, "translationX", UiUtil.getScreenWidth(),0f);
        layoutTransition.setAnimator(LayoutTransition.APPEARING, intAnimator);
        //加了下面两个效果感觉不是很好,而且效果也没出来
//      ObjectAnimator intOtherAnimator = ObjectAnimator.ofFloat(null, "rotationY", 0,90,0);
//      layoutTransition.setAnimator(LayoutTransition.CHANGE_APPEARING, intOtherAnimator);
//      
//      ObjectAnimator outOtherAnimator = ObjectAnimator.ofFloat(null, "rotationX", 0,-90,0);
//      layoutTransition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, outOtherAnimator);
        return layoutTransition;
    }
<1>可以定制dViewGroup的几个动画效果

我们可以定义的动画有一下几种:
*1.LayoutTransition.APPEARING 子View添加到容器中时的过渡动画效果。
*2.LayoutTransition.DISAPPEARING 子View从容器中移除时的过渡动画效果。
*3.LayoutTransition.CHANGE_DISAPPEARING 子View从容器中移除时,其它子view位置改变的过渡动画。
*4.LayoutTransition.CHANGE_APPEARING 子View添加到容器中时,其他子View位置改变的过渡动画。
*5.LayoutTransition.CHANGING 4.1 JellyBean上还有一个增强的功能,可以在容器内的子view的layout发生变化时也播放动画。
下面这段代码就是设置子View从容器中移除时,其它子view位置改变的过渡动画:

layoutTransition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, outOtherAnimator);
<2>LayoutTransition需要注意的问题

1.LayoutTransition.CHANGE_APPEARING和LayoutTransition.CHANGE_DISAPPEARING必须要使用PropertyValuesHolder构造的动画才有效
2.在构造PropertyValuesHolder动画时,”left”,”top”,”right”和”bottom”属性至少要写两个,而且如果是两个的时候,必须是左上,左下,右上,右下的模式,不能出现左右,上下的模式
3.对于LayoutTransition.CHANGE_APPEARING和LayoutTransition.CHANGE_DISAPPEARING,在构造PropertyValuesHolder时,所使用的ofInt,ofFloat中的参数值,第一个值和最后一个值必须相同,不然此属性所对应的的动画将被放弃,在此属性值上将不会有效果

    /**
     * http://blog.csdn.net/harvic880925/article/details/50985596
     * PropertyValuesHolder是用于同时执行多个动画,没必要像下面这样,只有一个动画就不必使用PropertyValuesHolder
     * 但是LayoutTransition有几个需要注意的问题:
     * 1.LayoutTransition.CHANGE_APPEARING和LayoutTransition.CHANGE_DISAPPEARING必须要使用PropertyValuesHolder构造的动画才有效
     * 2.在构造PropertyValuesHolder动画时,"left","top","right"和"bottom"属性至少要写两个,而且如果是两个的时候,必须是左上,左下,右上,右下的模式,不能出现左右,上下的模式
     * 3.对于LayoutTransition.CHANGE_APPEARING和LayoutTransition.CHANGE_DISAPPEARING,在构造PropertyValuesHolder时,所使用的ofInt,ofFloat中的参数值,第一个值和最后一个值必须相同,不然此属性所对应的的动画将被放弃,在此属性值上将不会有效果
     * @return
     */
    private LayoutTransition initCustomLayoutTransition2()
    {
        UiUtil.initialize(this);
        LayoutTransition layoutTransition = new LayoutTransition();
        PropertyValuesHolder outValuesHolder = PropertyValuesHolder.ofFloat("translationX", 0f,UiUtil.getScreenWidth());
        PropertyValuesHolder inValuesHolder = PropertyValuesHolder.ofFloat("translationX", UiUtil.getScreenWidth(),0f);
        ObjectAnimator outAnimator = ObjectAnimator.ofPropertyValuesHolder(bodyLayout,outValuesHolder);
        layoutTransition.setAnimator(LayoutTransition.DISAPPEARING, outAnimator);
        ObjectAnimator intAnimator = ObjectAnimator.ofPropertyValuesHolder(bodyLayout,inValuesHolder);
        layoutTransition.setAnimator(LayoutTransition.APPEARING, intAnimator);


        PropertyValuesHolder pvhLeft =
                PropertyValuesHolder.ofInt("left", 0, 0);
        PropertyValuesHolder pvhTop =
                PropertyValuesHolder.ofInt("top", 0, 0);
        PropertyValuesHolder pvhRight =
                PropertyValuesHolder.ofInt("right", 0, 0);
        PropertyValuesHolder pvhBottom =
                PropertyValuesHolder.ofInt("bottom", 0, 0);
        PropertyValuesHolder outOtherValuesHolder = PropertyValuesHolder.ofFloat("rotationY", 0,180,0);
        PropertyValuesHolder inOtherValuesHolder = PropertyValuesHolder.ofFloat("rotationX", 0,-180,0);
        ObjectAnimator intOtherAnimator = ObjectAnimator.ofPropertyValuesHolder(bodyLayout, pvhRight, pvhTop,outOtherValuesHolder);
        layoutTransition.setAnimator(LayoutTransition.CHANGE_APPEARING, intOtherAnimator);
        layoutTransition.setDuration(3000);
        ObjectAnimator outOtherAnimator = ObjectAnimator.ofPropertyValuesHolder(bodyLayout, pvhRight, pvhTop,inOtherValuesHolder);
        layoutTransition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, outOtherAnimator);
        return layoutTransition;
    }

4.Viewpager转场动画

Viewpager本来就有转场动画,但是我们还可以通过PageTransformer设置他的转场动画效果。官网的Using ViewPager for Screen Slides也有介绍。
其实我们要做的很简单,只需要自定义一个PageTransformer,然后在通过Viewpager的setPageTransformer方法设置即可。
当我们实现PageTransformer接口的时候,我们需要实现transformPage方法。里面的两个参数很关键:
View view 这个view即我们能看到的界面;
float position 这个是一个动态属性,是用来控制动画的重要参数;
下面我们通过例子来说明这两个参数。
首先,我给Viewpager的几个界面都设置一个id,pager1=111,pager2=222,pager3=333,这样我们就可以知道在切换界面的时候position 参数改变对应的是哪个view。

public class TestViewPagerActivity extends Activity{

    private ViewPager viewPager = null;
    private List<LinearLayout> pagers = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.test_viewpager);
        viewPager = (ViewPager) findViewById(R.id.view_pager);
        viewPager.setPageTransformer(true, new DepthPageTransformer());
        pagers = new ArrayList<LinearLayout>();
        Pager pager1 = new Pager(this);
        pager1.setId(111);
        pager1.setText("界面一");
        pager1.setBackgroundColor(Color.RED);
        Pager pager2 = new Pager(this);
        pager2.setId(222);
        pager2.setText("界面二");
        pager2.setBackgroundColor(Color.YELLOW);
        Pager pager3 = new Pager(this);
        pager3.setId(333);
        pager3.setText("界面三");
        pager3.setBackgroundColor(Color.BLUE);
        pagers.add(pager1);
        pagers.add(pager2);
        pagers.add(pager3);
        MyAdapter adapter = new MyAdapter();
        adapter.setList(pagers);
        viewPager.setAdapter(adapter);
    }

    private class MyAdapter extends PagerAdapter
    {
        private List<LinearLayout> list = null;


        public List<LinearLayout> getList() {
            return list;
        }

        public void setList(List<LinearLayout> list) {
            this.list = list;
        }

        @Override
        public int getCount() {

            return list!=null?list.size():0;
        }

        @Override
        public boolean isViewFromObject(View arg0, Object arg1) {

            return arg0==arg1;
        }
        @Override
        public void destroyItem(ViewGroup container, int position,
                Object object) {
            container.removeView(list.get(position));
        }
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            container.addView(list.get(position));
            return list.get(position);
        }
    }
}

然后实现我们自己的PageTransformer,在里面打个日志
Log.i(“lgy”, “position:”+position+” view:”+view.getId());

/**
 * @author LGY
 *View page :这个当然就是我们在ViewPager中滑动的界面。
 *float position :这个参数是动态改变的,是一个float类型,而不是平常我们所理解的int位置,只有很好的理解这个参数我们才能设计出我们想要的效果。
 *当position=-1时,表示当前页的前一页,此时该页面是看不见的
 *当position= 0时,表示当前页,当前显示页
 *当position=-1时,表示当前页的下一页
 *position取值为 [-Infinity,-1) -> 页面不可见
 *position取值为(1,+Infinity] -> 页面不可见
 *position取值为[-1,1] -> 于可见状态区间
  如果前一页和下一页基本各在屏幕占一半时,前一页的position是-0.5,后一页的posiotn是0.5,所以根据position的值我们就可以自行设置需要的alpha,x/y信息 
 */
public class DepthPageTransformer implements ViewPager.PageTransformer {
    private static final float MIN_SCALE = 0.75f;

    public void transformPage(View view, float position) {
        int pageWidth = view.getWidth();
        Log.i("lgy", "position:"+position+" view:"+view.getId());

        if (position < -1) { // [-Infinity,-1)[负无穷大,-1)
            // This page is way off-screen to the left.这一页是屏幕左边
            view.setAlpha(0);

        } else if (position <= 0) { // [-1,0]
            // Use the default slide transition when moving to the left page
            //当向左移动页面的时候,使用默认的幻灯片过渡
            view.setAlpha(1);
            view.setTranslationX(0);
            view.setScaleX(1);
            view.setScaleY(1);

        } else if (position <= 1) { // (0,1]
            // Fade the page out.页面消失了
            view.setAlpha(1 - position);

            // Counteract the default slide transition
            view.setTranslationX(pageWidth * -position);

            // Scale the page down (between MIN_SCALE and 1)
            float scaleFactor = MIN_SCALE
                    + (1 - MIN_SCALE) * (1 - Math.abs(position));
            view.setScaleX(scaleFactor);
            view.setScaleY(scaleFactor);

        } else { // (1,+Infinity]
            // This page is way off-screen to the right.
            view.setAlpha(0);
        }
    }
}

结果:当我向左滑动,界面一切换到显示界面二的时候的日志如下:

[Android][Animation]
从结果我们可以看出,在切换过程中界面一和界面二我们都可以看到,所以从日志里我们可以看到界面一和界面二的position参数。我们可以再看下面这个图理解

[Android][Animation]

这个图展示的是当界面一滑动到界面的一半的时候,界面一的拿到的position是-0.5,而界面而的position是0.5。
所以根据这个position参数就可以设置界面二的出现动画,如下的代码,我们知道界面二出现的过程中,position是从1到0这样变化的,所以view.setAlpha(1 - position);透明度是从0-1变化。

else if (position <= 1) { // (0,1]
            // Fade the page out.页面消失了
            view.setAlpha(1 - position);

            // Counteract the default slide transition
            view.setTranslationX(pageWidth * -position);

            // Scale the page down (between MIN_SCALE and 1)
            float scaleFactor = MIN_SCALE
                    + (1 - MIN_SCALE) * (1 - Math.abs(position));
            view.setScaleX(scaleFactor);
            view.setScaleY(scaleFactor);

        }

5.总结

其实还有好多细节没有点 出来,由于没有用到,说要就不探究那么仔细了。

6.参考文章

官方介绍动画的使用
Viewpager动画,这篇文章挺好的
http://blog.csdn.net/yegongheng/article/details/38435553
http://blog.csdn.net/javazejian/article/details/52571779
https://developer.android.com/guide/topics/graphics/view-animation.html
https://developer.android.com/guide/topics/graphics/prop-animation.html
https://developer.android.com/guide/topics/graphics/drawable-animation.html

7.源码地址

官方介绍动画的使用Demo
我的例子