美文网首页Android
[Android]属性动画简介(一)属性动画的实现和常用方法

[Android]属性动画简介(一)属性动画的实现和常用方法

作者: dafasoft | 来源:发表于2020-11-26 20:15 被阅读0次

    简单的属性动画的实现

    现在设计一个动画,让View从x坐标50处移动到x坐标400处

    使用ValueAnimator的实现
    public void startObjectAnimatorAnim(final View v) {
            ValueAnimator animator = ValueAnimator.ofFloat(50, 400);
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float value = (float) animation.getAnimatedValue();
                    v.setTranslationX(value);
                }
            });
            animator.setDuration(1000);
            animator.start();
        }
    

    ValueAnimaotr是最直接的属性动画的使用方式,ValueAnimator还有个子类ObjectAnimator

    ObjectAnimator的实现
       public void startObjectAnimatorAnim(View v) {
            ObjectAnimator animator = ObjectAnimator.ofFloat(v, "translationX", 50, 400);
            animator.setDuration(1000);
            animator.start();
        }
    

    非常简单的几行代码即可实现一个View的平移动画。同理,传递不同的属性和值,也会实现该View针对不同的属性的变化

    ofFloat第一个参数是需要进行动画的对象,第二个参数为该对象所支持的属性,后面为可变参数,传递的是该属性的值

    这里可能会有同学问第二个参数的取值有什么规则么?这里第二个参数的传值,跟第一个参数的类型有关系,这个我们后面分析源码时会讲

    使用PropertyValueHolder实现
    public void startObjectAnimatorAnim(final View v) {
            PropertyValuesHolder holder = PropertyValuesHolder.ofFloat("translationX", 40, 500);
            ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(v, holder);
            animator.setDuration(1000);
            animator.start();
        }
    

    效果图:


    42008ac2ae0b2d8e979e805ad52fe09e[00_00_00--00_00_04].gif

    动画组合效果的实现

    现在我们让View从50移动到400处时,透明度从100%逐渐变化到0%

    使用ValueAnimator实现
    ValueAnimator animator = ValueAnimator.ofFloat(0, 1f);
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float value = (float) animation.getAnimatedValue();
                    float translationX = 50 + 350 * value;
                    float alpha = 1 - value;
                    v.setTranslationX(translationX);
                    v.setAlpha(alpha);
                }
            });
            animator.setDuration(1000);
            animator.start();
    
    使用PropertyValueHolder实现:
    public void startObjectAnimatorAnim(final View v) {
            PropertyValuesHolder alphaHolder = PropertyValuesHolder.ofFloat("alpha", 1f, 0f);
            PropertyValuesHolder translationHolder = PropertyValuesHolder.ofFloat("translationX", 50, 400);
            ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(v, alphaHolder, translationHolder);
            animator.setDuration(1000);
            animator.start();
        }
    

    如果使用ObjectAnimator单独指定属性的方式,因为属性不能设置多个,所以不能满足需求,如想要实现,可借助AnimatorSet:

    AnimatorSet实现
    public void startObjectAnimatorAnim(final View v) {
            ObjectAnimator alphaAnim = ObjectAnimator.ofFloat(v, "alpha", 1, 0);
            alphaAnim.setDuration(1000);
            ObjectAnimator translationAnim = ObjectAnimator.ofFloat(v, "translationX", 50, 400);
            translationAnim.setDuration(1000);
            AnimatorSet animatorSet = new AnimatorSet();
            animatorSet.setDuration(1000);
            //animatorSet.playTogether(alphaAnim, translationAnim);
            animatorSet.play(alphaAnim).with(translationAnim);
            animatorSet.start();
        }
    

    AnimatorSet的其他常用方法:

    • animatorSet.play(animator1).with(animator2);动画1和动画2同时执行
    • animatorSet.play(animator3).after(animator2);动画3在动画2执行完成后执行
    • animatorSet.playSequentially(animator1,animator2,animator3)动画1,2,3按顺序执行
    • animatorSet.playTogether(animator1,animator2,animator3)三个动画同时执行
      效果图:


      translation_alpha.gif

    可以看到,ValueAnimator需要我们手动去计算值,这种方式更加繁琐确更加灵活,而使用ObjectAnimator直接指定属性和ObjectAnimator指定PropertyValueHolder的最终实现其实是一样的,这个我们先不讲,后面分析

    差值器

    新年又有新规定,现在要求小球做加速运动从50移动到400,因为动画默认是匀速的,想做加速运动就必须要借助差值器(Interpolator)了

    Interpolator负责控制动画变化的速率,使得基本的动画效果能够以匀速、加速、减速、抛物线速率等各种速率变化。

    动画的每一帧都将在开始和结束之间的特定时间显示,此时动画时间被转换为时间索引,则动画时间轴上的每个点都可以转换成0.0到1.0之间的一个浮点数。然后再将该值用于计算该对象的属性变换

    下面我们看一下加速动画的代码实现,因为这几种属性动画的实现都类似,我们接下来只演示ValueAnimator的实现

    代码:

    public void startObjectAnimatorAnim(final View v) {
            ValueAnimator animator = ValueAnimator.ofFloat(40, 500);
            animator.setInterpolator(new AccelerateInterpolator());
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float value = (float) animation.getAnimatedValue();
                    v.setTranslationX(value);
                }
            });
            animator.setDuration(2000);
            animator.start();
        }
    

    这里只比上面的实现增加了一句animator.setInterpolator(new AccelerateInterpolator());
    这句话的意思是在这个动画里增加了一个差值器,这个差值器的作用是将动画做加速运动

    这个AccelerateInterpolator是Android系统实现好的差值器,其它系统实现的差值器还有

            //加速查值器,参数越大,速度越来越快
            animator.setInterpolator(new AccelerateInterpolator(10));
            //减速差值起,和上面相反
            animator.setInterpolator(new DecelerateInterpolator(10));
            //先加速后减速差值器
            animator.setInterpolator(new AccelerateDecelerateInterpolator());
            //张力值,默认为2,T越大,初始的偏移越大,而且速度越快
            animator.setInterpolator(new AnticipateInterpolator(3));
            //张力值tension,默认为2,张力越大,起始时和结束时的偏移越大
            animator.setInterpolator(new AnticipateOvershootInterpolator(6));
            //弹跳差值器
            animator.setInterpolator(new BounceInterpolator());
            //周期差值器
            animator.setInterpolator(new CycleInterpolator(2));
            //线性差值器,匀速
            animator.setInterpolator(new LinearInterpolator());
    
    自定义差值器

    上面又来了规定中的规定,要求View运动时,前半段时间匀速,后半段时间加速,目前系统实现的差值器没有这种效果,这样就需要我们自己定义差值器了

    要自定义差值器也比较简单,只需要实现TimeInterpolator接口,并重新实现TimeInterpolator的getInterpolation即可 getInterpolation的入参就是在匀速状态下动画的完成度,我们针对入参做一些更改,即可实现各种各样的动画效果

    看下代码实现:

    public void startObjectAnimatorAnim(final View v) {
            ValueAnimator animator = ValueAnimator.ofFloat(40, 500);
            animator.setInterpolator(new CustomInterpolator());
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float value = (float) animation.getAnimatedValue();
                    v.setTranslationX(value);
                }
            });
            animator.setDuration(2000);
            animator.start();
        }
    
    // 自定义差值器   CustomInterpolator .java
    public class CustomInterpolator implements TimeInterpolator {
        @Override
        public float getInterpolation(float input) {
            if (input < 0.5f) {
                return input / 2;
            }
            return input * input;
        }
    }
    

    看下效果:


    custom_interpolator.gif

    估值器

    上面的规定越来越多,要求View运动时,前半段时间匀速,后半段时间加速,在到达400位置后,要有惯性效果,即超出一部分(假设运动到430位置)再弹回

    我们现在分析一下这种场景,如果想要到达位置后有个超出的效果,继续在CustomInterpolator基础上修改差值器逻辑会有些复杂,这个时候,可以自定义一个估值器来实现

    估值器是什么

    如果说差值器是动画在时间维度的变化的话,那么估值器就是动画在数值维度上的变化,其实差值器和估值器是配合使用的,如果我么什么也不操作,系统也会给我们默认生成一个差值器和估值器,而估值器用来计算的参数,也是通过差值器的计算给出的,这个我们后面分析源码的时候再讲

    下面我们看一下如何使用估值器实现上述效果

    自定义差值器的实现也很简单,只需要实现TypeEvaluator即可:

    /*** CustomEvaluator.java */
    public class CustomEvaluator implements TypeEvaluator<Float> {
    
        @Override
        public Float evaluate(float fraction, Float startValue, Float endValue) {
            if (fraction <= 0.8) {
                // 动画执行的前80% 走完全部路径
                return startValue + (endValue - startValue) / 0.8f * fraction;
            } else if (fraction <= 0.9) {
                // 动画执行的80%-90%时走到430处
                return endValue + 30 * (fraction - 0.8f) / 0.1f;
            } else {
                // 动画执行的90%-100%时返回400处
               return endValue + 30 - 30 * (fraction - 0.9f) / 0.1f;
            }
        }
    }
    
    /**** MainActivity */
    public void startObjectAnimatorAnim(final View v) {
            ValueAnimator animator = ValueAnimator.ofObject(new CustomEvaluator(), 50f, 400f);
            animator.setInterpolator(new CustomInterpolator());
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    float value = (float) animation.getAnimatedValue();
                    v.setTranslationX(value);
                }
            });
            animator.setDuration(2000);
            animator.start();
        }
    

    效果图:


    type_evaluator.gif

    关键帧

    上面的规定没完没了,现在要求View从50匀速移动到400,在动画运行的前半段透明度为100% 后半段从100%变为0%

    我们一看,哦 上面的规定也蛮简单的嘛,通过ValueAnimator AnimatorSet 这不都能做么 有没有其他办法呢?
    我们来尝试一下新方案

    public void startObjectAnimatorAnim(final View v) {
            PropertyValuesHolder alphaHolder = PropertyValuesHolder.ofFloat("alpha", 1f, 1f, 0f);
            PropertyValuesHolder translationHolder = PropertyValuesHolder.ofFloat("translationX", 50, 400);
            ObjectAnimator animator = ObjectAnimator.ofPropertyValuesHolder(v, alphaHolder, translationHolder);
            animator.setDuration(1000);
            animator.start();
        }
    

    效果图:


    key_frame.gif

    这里和上面那个案例唯一的区别就是alphaHolder可变参数那里,上面的案例可变参数是2个,这里变成了三个,这里每一个参数都是一个关键帧,它们用来标记动画执行的不同阶段,通过关键帧,我们可以做的变换有多了一些

    以上就是属性动画的常用方式和方法,使用起来还是比较简单的,而且功能也比较强大,反正我是比较喜欢用属性动画去实现一些UI效果的

    相关文章

      网友评论

        本文标题:[Android]属性动画简介(一)属性动画的实现和常用方法

        本文链接:https://www.haomeiwen.com/subject/zckniktx.html