[置顶] 安卓属性动画详解

这是一份学习总结,简单地介绍了一下,罗列了一下常用的属性,并非全部原创,底部附上参考网址。

大家可以将这些代码直接拷贝到自己的工程中使用,参数传入View即可,有什么问题或者意见欢迎留言。

在View Animation(Tween Animation)中,其改变的是View的绘制效果,真正的View的属性保持不变,就比如说一个按钮,改变了大小之后,其实可点击的范围是不变的。而在Property Animation中,改变的是对象的实际属性。而且Property Animation不止可以应用于View,还可以应用于任何对象。Property Animation只是表示一个值在一段时间内的改变,当值改变时要做什么事情完全是你自己决定的。

Property Animation

Duration:动画的持续时间
TimeInterpolation:属性值的计算方式,如先快后慢
TypeEvaluator:根据属性的开始、结束值与TimeInterpolation计算出的因子计算出当前时间的属性值
RepeatCountryandbehavoir:重复次数与方式,如播放3次、5次、无限循环,可以此动画一直重复,或播放完时再反向播放
Animationsets:动画集合,即可以同时对一个对象应用几个动画,这些动画可以同时播放也可以对不同动画设置不同开始偏移
FramereFreashDelay:多少时间刷新一次,即每隔多少时间计算一次属性值,默认为10ms,最终刷新时间还受系统进程调度与硬件的影响

Java代码中的通用属性:

setDuration(long durationMillis):设置动画持续事件(单位:毫秒)
setFillAfter(boolean fillAfter):如果fillAfter设为true,则动画执行后,控件将停留在动画结束的状态
setFillBefore(boolean fillBefore):如果fillBefore设为true,则动画执行后,控件将回到动画开始的状态
setStartOffset(long startOffset):设置动画执行之前等待的时间(单位:毫秒)
setRepeatCount(int repeatCount):设置动画重复的次数
setInterpolator(Interpolator i):设置动画的变化速度

TimeInterpolator插值器:

通过setInterpolator(Interpolator i)设置插值器,可以设置变化的速度
Time interplator定义了属性值变化的方式,如线性均匀改变,开始慢然后逐渐快等。在Property Animation中是TimeInterplator,在View Animation中是Interplator,这两个是一样的,在3.0之前只有Interplator,3.0之后实现代码转移至了TimeInterplator。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,以上几个都是实现了这个接口

Xml中通用的属性:

android:duration:设置动画持续时间
android:fillAfter:如果fillAfter设为true,则动画执行后,控件将停留在动画结束的状态
android:fillBefore:如果fillBefore设为true,则动画执行后,控件将回到动画开始的状态
android:startOffset(long startOffset):设置动画执行之前等待的时间(单位:毫秒)
android:repeatCount(int repeatCount):设置动画重复的次数
android:interpolator:设置动画的变化速度

TimeInterpolator插值器:

android:interpolator=”@android:anim/accelerate_decelerate_interpolator”:先加速,后减速
android:interpolator=”@android:anim/accelerate_interpolator”:加速
android:interpolator=”@android:anim/decelerate_interpolator”:减速
android:interpolator=”@android:anim/cycle_Interpolator”:动画循环播放特定次数,速率改变沿着正弦曲线
android:interpolator=”@android:anim/linear_Interpolator”:匀速

ValueAnimato

概述:

在ObjectAnimato解决不了的动画上再考虑用它吧,使用起来比ObjectAnimato更加灵活
ValueAnimator即表示一个动画,包含动画的开始值,结束值,持续时间等属性,包含Property Animation动画的所有核心功能,如动画时间,开始、结束属性值,相应时间属性值计算方法等。ValueAnimator封装了一个TimeInterpolator,TimeInterpolator定义了属性值在开始值与结束值之间的插值方法。ValueAnimator还封装了一个TypeAnimator,根据开始、结束值与TimeIniterpolator计算得到的值计算出属性值。

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

TypeEvaluator

这个对象返回动画所需的参数,比如东西要移动到哪个坐标,需要返回一个Point,前提是你将参数类型设置为Point,在第二个案例中使用自定义Evaluator。
根据属性的开始、结束值与TimeInterpolation计算出的因子计算出当前时间的属性值,android提供了以下几个evalutor:

  • IntEvaluator:属性的值类型为int;
  • FloatEvaluator:属性的值类型为float;
  • ArgbEvaluator:属性的值类型为十六进制颜色值;
  • TypeEvaluator:一个接口,可以通过实现该接口自定义Evaluator

这里举两个案例:

 /** * 自由落体 * * @param view */
    public void verticalFall(final View view) {
        //设置动画的开始、结束位置
        ValueAnimator animator = ValueAnimator.ofFloat(0, view.getHeight());
        animator.setTarget(view);
        //设置动画时间
        animator.setDuration(1000).start();
        //设置一个加速的插值器
        animator.setInterpolator(new AccelerateInterpolator());
        //添加一个更新事件监听,通过参数设置view的位置
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //根据返回值设置view的位置
                view.setTranslationY((Float) animation.getAnimatedValue());
            }
        });
    }
     /** * 抛物线 * * @param view */
    public void paowuxian(final View view) {
        ValueAnimator valueAnimator = new ValueAnimator();
        valueAnimator.setDuration(3000);
        //手动指定TypeValue,用于接受计算出属性值
        valueAnimator.setObjectValues(new PointF(0, 0));
        //匀速变化
        valueAnimator.setInterpolator(new LinearInterpolator());
        //计算结果值,以我们指定的TypeValue返回结果
        valueAnimator.setEvaluator(new TypeEvaluator<PointF>() {
            @Override
            public PointF evaluate(float fraction, PointF startValue,
                                   PointF endValue) {
                // 这里需要明确fraction是当前时间占总时间的大小:fraction = t / duration
                PointF point = new PointF();
                //(fraction * 3)为当前时间,水平速度为(10t)*10
                point.x = 10*10 * fraction * 3;
                //垂直速度为(1/2gt^2)*10,顺便说一下,乘法计算速度会比除法快
                point.y = 10*0.5f * 9.8f * (fraction * 3) * (fraction * 3);
                return point;
            }
        });

        valueAnimator.start();
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                //在这里接收返回的PointF,然后设置View的坐标
                PointF point = (PointF) animation.getAnimatedValue();
                view.setX(point.x);
                view.setY(point.y);
            }
        });
    }

动画监听事件

动画播放的时候再插入事件,这里只实现了一个淡出的功能,大家是不是可以考虑在旋转到180的时候,替换图片背景,做出类似于翻页的动画特效?
Animator.AnimatorListener包含了动画变化的四种状态变化的事件监听:

  • onAnimationStart()
  • onAnimationEnd():可以制作view淡入淡出的效果
  • onAnimationRepeat():重复的时候触发,例如用在计时
  • onAnimationCancel():cancel动画立即停止,停在当前的位置
 /** * 控件淡出且remove * * @param view */
    public void fadeOut(final View view) {
        ObjectAnimator anim = ObjectAnimator.ofFloat(view, "alpha", 0.5f);
        anim.addListener(new Animator.AnimatorListener() {

            @Override
            public void onAnimationStart(Animator animation) {
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                ViewGroup parent = (ViewGroup) view.getParent();
                if (parent != null)
                    parent.removeView(view);
            }

            @Override
            public void onAnimationCancel(Animator animation) {
            }
        });
        anim.start();
    }

可以继承AnimatorListenerAdapter而不是实现AnimatorListener接口来简化操作,这个类对AnimatorListener中的函数都定义了一个空函数体,这样我们就只用定义想监听的事件而不用实现每个函数却只定义一空函数体。
使用AnimatorListenerAdapter进行代码优化:

  /** * 控件淡出并且remove * * @param view */
    public void fadeOut(final View view) {
        ObjectAnimator anim = ObjectAnimator.ofFloat(view, "alpha", 0.5f);
        anim.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                ViewGroup parent = (ViewGroup) view.getParent();
                if (parent != null)
                    parent.removeView(view);
            }
        });
        anim.start();
    }

ObjectAnimator

概述:

最简单的动画,传入四个参数:view,变化的类型,状态值(任意多个)即可,但是受制于get方法,若是没有get方法,这时候,可以考虑使用ValueAnimator
继承自ValueAnimator,当属性值计算完成时自动设置为该对象的相应属性,自动完成Property Animation的全部操作。要想使用ObjectAnimator,应该满足以下条件:

  • 对象应该有一个setter函数:set(驼峰命名法)
  • 像ofFloat之类的工场方法,第一个参数为对象名,第二个为属性名,后面的参数为可变参数,如果values…参数只设置了一个值的话,那么会假定为目的值,属性值的变化范围为当前值到目的值,为了获得当前值,该对象要有相应属性的getter方法:get,如果有getter方法,其应返回值类型应与相应的setter方法的参数类型一致。

可选参数

可选择的变化类型,要是写漏了,欢迎补充
在Android 3.0中给View增加了一些参数并对这些参数增加了相应的getter/setter函数(ObjectAnimator要用这些函数改变这些属性):

  • translationX,translationY: View相对于原始位置的偏移量
  • rotation,rotationX,rotationY: 旋转,rotation用于2D旋转角度,3D中用到后两个
  • scaleX,scaleY: 缩放比
  • x,y: View的最终坐标,是View的left,top位置加上translationX,translationY
  • alpha: 透明度

注:rotationX,是沿着高度一半的那一根水平线旋转,可以通过代码设置pivotX和pivotY,然后调用invalidate重新绘制

    /** * 图标沿着x轴中心旋转 * * @param view */
    public void rotateyX(View view) {
        ObjectAnimator
    //1500毫秒内view沿着中心x轴从0度旋转360度
                .ofFloat(view, "rotationX", 0.0F, 360.0F)
                .setDuration(1500)
                .start();
    }

手动地实现addUpdateListener方法,使ObjectAnimator使用更加灵活,用法与ValueAnimator相同

 /** * ObjectAnimator的使用 * 动画效果组合,淡入淡出,缩小放大 * * @param view */
    public void ZoomInZoomOut(final View view) {
        ObjectAnimator anim = ObjectAnimator
                //参数指定3个,1到0到1
                .ofFloat(view, "这个参数任意指定", 1.0F, 0.0F, 1.0F)
                //时间0.5秒
                .setDuration(500);//
        anim.start();
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float cVal = (Float) animation.getAnimatedValue();
                //透明度,不透明到透明再到不透明
                view.setAlpha(cVal);
                //x轴变化,由1到0再到1
                view.setScaleX(cVal);
                //y轴变化,由1到0再到1
                view.setScaleY(cVal);
            }
        });
    }

PropertyValuesHolder

更简单的方式,实现一个动画多个效果
如果需要对一个View的多个属性进行动画可以用ViewPropertyAnimator类,该类对多属性动画进行了优化,会合并一些invalidate()来减少刷新视图,该类在3.1中引入。

public void propertyValuesHolder(View view) {
        //淡入淡出
        PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("alpha", 1f,
                0f, 1f);
        //x轴放大缩小
        PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("scaleX", 1f,
                0, 1f);
        //y轴放大缩小
        PropertyValuesHolder pvhZ = PropertyValuesHolder.ofFloat("scaleY", 1f,
                0, 1f);
        ObjectAnimator.ofPropertyValuesHolder(view, pvhX, pvhY, pvhZ).setDuration(1000).start();
    }

AnimatorSet

多个动画花样组合
playTogether:就是把好多个动画放在一起执行
复杂组合:play()当前动画,with()添加一个和当前动画同时执行的动画,after()添加一个动画在当前动画之后执行;

 /** * AnimatorSet的使用:动画同时执行 * anim1,anim2同时执行 * * @param view */
    public void togetherRun(View view) {
        //沿着x、y轴放大一倍
        ObjectAnimator anim1 = ObjectAnimator.ofFloat(view, "scaleX",
                1.0f, 2f);
        ObjectAnimator anim2 = ObjectAnimator.ofFloat(view, "scaleY",
                1.0f, 2f);
        AnimatorSet animSet = new AnimatorSet();
        animSet.setDuration(2000);
        animSet.setInterpolator(new LinearInterpolator());
        //两个动画同时执行
        animSet.playTogether(anim1, anim2);
        animSet.start();
    }

    /** * AnimatorSet的使用:动画顺序执行 * * @param view */
    public void playWithAfter(View view) {
        float cx = view.getX();

        ObjectAnimator anim1 = ObjectAnimator.ofFloat(view, "scaleX",
                1.0f, 2f);
        ObjectAnimator anim2 = ObjectAnimator.ofFloat(view, "scaleY",
                1.0f, 2f);
        ObjectAnimator anim3 = ObjectAnimator.ofFloat(view,
                "x", cx, 0f);
        ObjectAnimator anim4 = ObjectAnimator.ofFloat(view,
                "x", cx);

        AnimatorSet animSet = new AnimatorSet();
       //anim1,anim2和anim3同时,anim4在他们之后
        animSet.play(anim1).with(anim2);
        animSet.play(anim2).with(anim3);
        animSet.play(anim4).after(anim3);
        animSet.setDuration(1000);
        animSet.start();
    }

LayoutTransition

系统自带过渡动画,两三行代码,优化你增删控件的视觉效果
在Android应用开发的时候经常会用到View的setVisibility()方法来动态隐藏和显示view,但是这样子是没有过渡动画的,变化的时候会显得很生硬。LayoutTransition是一个在4.0新引入的Api,主要功能是在ViewGroup的layout发生变化的时候能够自动创建动画。具体使用的时候,首先创建一个LayoutTransition对象,并在容器布局调用setLayoutTransition(LayoutTransition)方法。这样,每当有子view从容器中出现或消失的时候,默认的animator就会被自动调用。当然,你也可以通过setAnimator()来设置自定义的动画。

复杂实现:

/**
* 可以修改下列代码,删除部分不需要的效果
* @return
*/
public LayoutTransition getTransition() {
LayoutTransition transition = new LayoutTransition();
transition.setAnimator(LayoutTransition.CHANGE_APPEARING,
transition.getAnimator(LayoutTransition.CHANGE_APPEARING));
transition.setAnimator(LayoutTransition.APPEARING,
transition.getAnimator(LayoutTransition.APPEARING));
transition.setAnimator(LayoutTransition.DISAPPEARING,
transition.getAnimator(LayoutTransition.DISAPPEARING));
transition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING,
transition.getAnimator(LayoutTransition.CHANGE_DISAPPEARING));
return transition;
}

//设置Transition
mGridLayout.setLayoutTransition(getTransition());

嫌麻烦就这样:

ViewGroup  container = (ViewGroup) findViewById(R.id.container);
LayoutTransition transition = new LayoutTransition();
container.setLayoutTransition(transition);

或者这样:

此外还有一个更简单地使用方法,在xml文件中我们在容器的中下面一句代码:

android:animateLayoutChanges="true"

还可以这样:

可以在容器内的子view的layout发生变化时也播放动画,用法如下。

LayoutTransition transition = container.getLayoutTransition();
transition.enableTransitionType(LayoutTransition.CHANGING);

参考:

http://www.2cto.com/kf/201411/353170.html
http://blog.csdn.net/harvic880925/article/details/40049763
http://www.jianshu.com/p/a03013850ccb

你可能感兴趣的:(android,动画)