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());
网友评论