美文网首页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