动画

作者: _Rice_ | 来源:发表于2020-04-01 23:41 被阅读0次

    Matrix

    作用就是坐标映射,转成实际的坐标位置。
    基本变换有4种: 平移(translate)、缩放(scale)、旋转(rotate) 和 错切(skew)。

    帧动画

    原理:就是将一张张单独的图片连贯的进行播放
    缺点:这种动画效果单一,性能差,占用内存高

    补间动画

    比帧动画性能好,效果多,动画更加连贯。

    间动画仅仅是对 View 在视觉效果上做了移动、缩放、旋转和淡入淡出的效果,其实并没有真正改变 View 的属性。
    补间动画的核心本质就是在一定的持续时间内,不断改变 Matrix 变换,并且不断刷新的过程。invalidate

    补间动画所操作的 Matrix,其实是借用了它父容器的一个叫 mChildTransformation 的属性 ( 里面有 Matrix ),通过 getChildTransformation 获得。
    也就是说,一个 ViewGroup 中,无论它有几个子 View 都好,在这些子 View 播放补间动画的时候,都是共用同一个 Transformation 对象的(也就是共用一个 Matrix ),这个对象放在 ViewGroup 里面。

    属性动画

    功能非常强大,弥补了之前补间动画的一些缺陷,几乎是可以完全替代掉补间动画了。

    优点:可以自定义动画,实现复杂动画效果。最重要的是可以改变属性动画的值,不会影响动画执行后的位置正常使用
    其实就是在一定的时间间隔内,通过不断地对值进行改变,并不断将该值赋给对象的属性,从而实现该对象在属性上的动画效果。
    对于属性动画来说,尤其需要注意的是操作的属性需要有 set 和 get 方法,不然你的 ObjectAnimator 操作就不会生效。

    属性动画所影响的 Matrix,是在 View 的 mRenderNode 中的 stagingProperties 里面的,这个 Matrix 在每个 View 之间都是独立的,所以可以各自保存不同的变换状态。

    性能分析

    属性动画操作的是对象的实例属性,例如translationX,然后反射调用set,get方法,多个属性动画同时执行,会频繁反射调用类方法,降低性能。
    属性动画虽然会反射,但是也会用hashMap缓存反射过的method,进行复用。

    补间动画只产生了一个动画效果,其真实的坐标并没有发生改变,是效果一直在发生变化,没有频繁反射调用方法的耗费性能操作。
    不过补间动画执行完成后,不回置动画效果,对于事件点击容易产生困扰。而属性动画因为操作了类的属性,也就是View的top,left,height,width等,没有补间动画的问题

    ValueAnimator 类 & ObjectAnimator 类,二者的区别在于:

    ValueAnimator 类

    是先改变值,然后 手动赋值 给对象的属性从而实现动画;是 间接 对对象属性进行操作;而 ValueAnimator 类本质上是一种 改变值 的操作机制。

    只需要将初始值和结束值提供给ValueAnimator,并且告诉它动画所需运行的时长,那么ValueAnimator就会自动帮我们完成从初始值平滑地过渡到结束值这样的效果

    ValueAnimator anim = ValueAnimator.ofFloat(0f, 1f);
    anim.setDuration(300);
    anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            float currentValue = (float) animation.getAnimatedValue();
            Log.d("TAG", "cuurent value is " + currentValue);
        }
    });
    anim.start();
    
    

    ValueAnimator.ofXXX

    实际使用:根据计算出来的值不断改变控件的高度,实现控件展开和折叠效果。

    ObjectAnimator 类

    是先改变值,然后 自动赋值 给对象的属性从而实现动画;是 直接 对对象属性进行操作;可以理解为:ObjectAnimator 更加智能、自动化程度更高。

    当ViewGroup分派事件的时候,会正确的将当前触摸坐标,转换成矩阵变化后的坐标

    继承与ValueAnimator

    原理:根据已执行动画时间百分比计算插值分数,用插值分数计算估算值,更新属性值。

    //设置要执行动画效果的view,要改变的属性值,开始值,结束值
    ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);
    //动画时间
    animator.setDuration(5000);
    animator.start();
    

    ObjectAnimator.ofXXX

    根据传入的属性名,去寻找属性名对应的get和set方法。通过反射,通过hashmap缓存反射过的method方法。

    常用属性

    • translationX和translationY:这些属性控制View所在的位置,作为由其布局容器设置的左侧和顶部坐标的增量。
    • rotation,rotationX和rotationY:这些属性控制2D(rotation属性)中的旋转和围绕轴点的3D。
    • scaleX和scaleY:这些属性控制View围绕其轴心点的2D缩放。
    • pivotX和pivotY:这些属性控制枢轴点的位置,围绕该枢轴点进行旋转和缩放变换。默认情况下,轴心点位于对象的中心。
    • x和y:这些是简单的实用程序属性,用于描述View在其容器中的最终位置,作为左值和顶值以及translationX和translateY值的总和。
    • alpha:表示视图上的Alpha透明度。默认情况下,此值为1(不透明),值为0表示完全透明(不可见)。

    实际运用:用AnimatorSet内传ObjectAnimator,对身份证进行放缩位移操作

    组合动画 AnimatorSet

    实现组合动画功能主要需要借助AnimatorSet这个类,这个类提供了一个play()方法,如果我们向这个方法中传入一个Animator对象(ValueAnimator或ObjectAnimator)将会返回一个AnimatorSet.Builder的实例,AnimatorSet.Builder中包括以下四个方法:

    ObjectAnimator moveIn = ObjectAnimator.ofFloat(textview, "translationX", -500f, 0f);
    ObjectAnimator rotate = ObjectAnimator.ofFloat(textview, "rotation", 0f, 360f);
    ObjectAnimator fadeInOut = ObjectAnimator.ofFloat(textview, "alpha", 1f, 0f, 1f);
    AnimatorSet animSet = new AnimatorSet();
    animSet.play(rotate).with(fadeInOut).after(moveIn);
    animSet.setDuration(5000);
    animSet.start();
    
    

    Animator监听器

    ObjectAnimator是继承自ValueAnimator的,而ValueAnimator又是继承自Animator的,因此不管是ValueAnimator还是ObjectAnimator都是可以使用addListener()这个方法的。另外AnimatorSet也是继承自Animator的,因此addListener()这个方法算是个通用的方法。

    anim.addListener(new AnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {
        }
     
        @Override
        public void onAnimationRepeat(Animator animation) {
        }
     
        @Override
        public void onAnimationEnd(Animator animation) {
        }
     
        @Override
        public void onAnimationCancel(Animator animation) {
        }
    });
    

    适配器对象,单独重写onAnimationEnd

    
    anim.addListener(new AnimatorListenerAdapter() {
        @Override
        public void onAnimationEnd(Animator animation) {
        }
    });
    

    Evaluator

    通过计算告知动画系统如何从初始值过度到结束值

    ValueAnimator.ofFloat(),系统内置了一个FloatEvaluator,实现了TypeEvaluator接口,然后重写evaluate()方法。

    public class FloatEvaluator implements TypeEvaluator {
        public Object evaluate(float fraction, Object startValue, Object endValue) {
            float startFloat = ((Number) startValue).floatValue();
            return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
        }
    }
    
    • 第一个参数fraction非常重要,这个参数用于表示动画的完成度的,我们应该根据它来计算当前动画的值应该是多少
    • 第二第三个参数分别表示动画的初始值和结束值。那么上述代码的逻辑就比较清晰了,用结束值减去初始值,算出它们之间的差值,然后乘以fraction这个系数,再加上初始值,那么就得到当前动画的值了。

    Interpolator

    它的主要作用是可以控制动画的变化速率

    接口TimeInterpolator
    仅有这个方法float getInterpolation(float input);

    input这个参数的值会随着动画的运行而不断变化,不过它的变化是非常有规律的,就是根据设定的动画时长匀速增加,变化范围是0到1。也就是说当动画一开始的时候input的值是0,到动画结束的时候input的值是1,而中间的值则是随着动画运行的时长在0到1之间变化的。

    Evaluator中fraction和input的关系?

    input的值决定了fraction的值。input的值是由系统经过计算后传入到getInterpolation()方法中的,然后我们可以自己实现getInterpolation()方法中的算法,根据input的值来计算出一个返回值,而这个返回值就是fraction了。

    系统默认的Interpolator其实就是一个先加速后减速的Interpolator,对应的实现类就是AccelerateDecelerateInterpolator。
    调用Animator的setInterpolator()方法

    设置Interpolator

    private void startAnimation() {
        Point startPoint = new Point(getWidth() / 2, RADIUS);
        Point endPoint = new Point(getWidth() / 2, getHeight() - RADIUS);
        ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                currentPoint = (Point) animation.getAnimatedValue();
                invalidate();
            }
        });
        //设置Interpolator
        anim.setInterpolator(new BounceInterpolator());
        anim.setDuration(3000);
        anim.start();
    }
    
    

    安卓有很多内置的Interpolator,我们也可以自定义Interpolator

    
    public class DecelerateAccelerateInterpolator implements TimeInterpolator{
     
        @Override
        public float getInterpolation(float input) {
            float result;
            if (input <= 0.5) {
                result = (float) (Math.sin(Math.PI * input)) / 2;
            } else {
                result = (float) (2 - Math.sin(Math.PI * input)) / 2;
            }
            return result;
        }
     
    

    ViewPropertyAnimator

    为View的动画操作提供一种更加便捷的用法

    ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 0f);
    animator.start();
    

    用ViewPropertyAnimator实现

    textview.animate().alpha(0f);
    
    textview.animate().x(500).y(500);
    
    textview.animate().x(500).y(500).setDuration(5000)
            .setInterpolator(new BounceInterpolator());
    

    https://blog.csdn.net/guolin_blog/article/details/44171115

    相关文章

      网友评论

          本文标题:动画

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