动画

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

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