[Android][Animation]

来源:互联网 发布:淘宝考试题和答案2017 编辑:程序博客网 时间:2024/06/03 18:28

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);        }    }}

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

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

解析position参数

这个图展示的是当界面一滑动到界面的一半的时候,界面一的拿到的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
我的例子

原创粉丝点击