估值器(TypeEvaluator)
设置动画 如何从初始值 过渡到 结束值 的逻辑
- 插值器(
Interpolator)决定 值 的变化模式(匀速、加速)
- 估值器(
TypeEvaluator)决定 值 的具体变化数值
ValueAnimator
实现原理 : 通过不断控制 值的变化, 再不断赋值给对象的属性,从而实现动画的效果。
从上面原理可以看出:ValueAnimator类中有3个重要方法:
ValueAnimator.ofInt(int values)
ValueAnimator.ofFloat(float values)
ValueAnimator.ofObject(int values)
ValueAnimator.ofInt(int values)
将初始值 以整型数值的形式 过渡到结束值
即估值器是整型估值器 - IntEvaluator
模板代码
实际开发中,建议使用Java代码实现属性动画:因为很多时候属性的起始值是无法提前确定的(无法使用XML设置),这就需要在Java代码里动态获取。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
| ValueAnimator anim = ValueAnimator.ofInt(0, 3);
anim.setDuration(500); anim.setStartDelay(500);
anim.setRepeatCount(0); anim.setRepeatMode(ValueAnimator.RESTART);
anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) {
int currentValue = (Integer) animation.getAnimatedValue(); System.out.println(currentValue);
View.setproperty(currentValue);
View.requestLayout(); } });
anim.start(); }
public static ValueAnimator ofInt(int... values) { ValueAnimator anim = new ValueAnimator(); anim.setIntValues(values); return anim; }
|
XML设置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| // ValueAnimator采用<animator> 标签 <animator xmlns:android="http://schemas.android.com/apk/res/android" android:valueFrom="0" // 初始值 android:valueTo="100" // 结束值 android:valueType="intType" // 变化值类型 :floatType & intType
android:duration="3000" // 动画持续时间(ms),必须设置,动画才有效果 android:startOffset ="1000" // 动画延迟开始时间(ms) android:fillBefore = “true” // 动画播放完后,视图是否会停留在动画开始的状态,默认为true android:fillAfter = “false” // 动画播放完后,视图是否会停留在动画结束的状态,优先于fillBefore值,默认为false android:fillEnabled= “true” // 是否应用fillBefore值,对fillAfter值无影响,默认为true android:repeatMode= “restart” // 选择重复播放动画模式,restart代表正序重放,reverse代表倒序回放,默认为restart| android:repeatCount = “0” // 重放次数(所以动画的播放次数=重放次数+1),为infinite时无限重复 android:interpolator = @[package:]anim/interpolator_resource // 插值器,即影响动画的播放速度,下面会详细讲 />
|
1 2 3 4 5 6 7 8
| Animator animator = AnimatorInflater.loadAnimator(context, R.animator.set_animation);
animator.setTarget(view);
animator.start();
|
实战
按钮的宽度从 200px 放大到 500px
1 2 3 4 5 6
| <Button android:id="@+id/bt_value_anim" android:layout_width="200px" android:layout_height="wrap_content" android:layout_centerInParent="true" android:text="动画" />
|
?代码设置初始值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| val valueAnimator = ValueAnimator.ofInt(bt_value_anim.layoutParams.width, 600)
valueAnimator.duration = 2000
valueAnimator.addUpdateListener { val currentValue = it.animatedValue Timber.d("currentValue $currentValue")
bt_value_anim.layoutParams.width = currentValue as Int
bt_value_anim.requestLayout() }
valueAnimator.start()
|
浮点型:ValueAnimator.oFloat()
将初始值 以浮点型数值的形式 过渡到结束值
ValueAnimator.oFloat()采用默认的浮点型估值器 (FloatEvaluator)
ValueAnimator.ofInt()采用默认的整型估值器(IntEvaluator)
在使用上完全没有区别
ValueAnimator.ofObject()
将初始值 以对象的形式 过渡到结束值
即通过操作 对象 实现动画效果
实战
可以看到 ValueAnimator.ofObject()的本质还是操作 值,将多个值封装到一个对象里的方式,同时对多个值一起操作
PointEvaluator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class PointEvaluator : TypeEvaluator<Point> { override fun evaluate(fraction: Float, startValue: Point?, endValue: Point?): Point {
val startPoint = startValue val endPoint = endValue
val x = startPoint!!.x + fraction * (endPoint!!.x - startPoint!!.x) val y = startPoint!!.y + fraction * (endPoint!!.y - startPoint!!.y)
val point = Point(x,y) return point } }
|
Point
1
| class Point(val x: Float, val y: Float)
|
MyView
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
| class MyView : View {
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
val RADIUS = 70f
private var currentPoint : Point? = null val mPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply { color = Color.BLUE }
init {
}
override fun onDraw(canvas: Canvas?) {
if (currentPoint == null) { currentPoint = Point(RADIUS, RADIUS) val x = currentPoint?.x val y = currentPoint?.y if (x != null && y != null) { canvas?.drawCircle(x, y, RADIUS, mPaint) } val startPoint = Point(RADIUS, RADIUS)
val endPoint = Point(700f, 1000f)
val anim = ValueAnimator.ofObject(PointEvaluator(), startPoint, endPoint)
anim.duration = 5000
anim.addUpdateListener { currentPoint = it.animatedValue as Point? Timber.d("currentPoint==null ${currentPoint?.x} ${currentPoint?.y}") invalidate() } anim.start() } else {
val x = currentPoint!!.x val y = currentPoint!!.y canvas?.drawCircle(x, y, RADIUS, mPaint) Timber.d("currentPoint currentPoint!=null ${currentPoint?.x} ${currentPoint?.y}")
} } }
|
插值器
xml设置
当在XML文件设置插值器时,只需传入对应的插值器资源ID即可
主要是设置插值器属性android:interpolator
1 2 3 4 5 6 7 8 9 10 11 12 13
| <?xml version="1.0" encoding="utf-8"?> <scale xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/overshoot_interpolator" // 通过资源ID设置插值器 android:duration="3000" android:fromXScale="0.0" android:fromYScale="0.0" android:pivotX="50%" android:pivotY="50%" android:toXScale="2" android:toYScale="2" /> >
|
代码设置
当在Java代码设置插值器时,只需创建对应的插值器对象即可
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| Button mButton = (Button) findViewById(R.id.Button);
Animation alphaAnimation = new AlphaAnimation(1,0);
alphaAnimation.setDuration(3000); Interpolator overshootInterpolator = new OvershootInterpolator();
alphaAnimation.setInterpolator(overshootInterpolator);
mButton.startAnimation(alphaAnimation);
|
系统内置插值器

自定义插值器
根据动画的进度(0%-100%)计算出当前属性值改变的百分比
自定义插值器需要实现 Interpolator / TimeInterpolator接口 & 复写getInterpolation()
- 补间动画 实现
Interpolator接口;属性动画实现TimeInterpolator接口
TimeInterpolator接口是属性动画中新增的,用于兼容Interpolator接口,这使得所有过去的Interpolator实现类都可以直接在属性动画使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public interface Interpolator {
float getInterpolation(float input) { ...
return xxx; }
public interface TimeInterpolator { float getInterpolation(float input); }
|
匀速插值器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| @HasNativeInterpolator public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory { ... public float getInterpolation(float input) { return input; }
@HasNativeInterpolator public class AccelerateDecelerateInterpolator implements Interpolator, NativeInterpolatorFactory { ... public float getInterpolation(float input) { return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f; } }
|
先加速再减速 插值器:AccelerateDecelerateInterpolator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @HasNativeInterpolator public class AccelerateDecelerateInterpolator implements Interpolator, NativeInterpolatorFactory { ... public float getInterpolation(float input) { return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f; } }
|
对input值 根据动画的进度(0%-100%)通过逻辑计算 计算出当前属性值改变的百分比
实战
DecelerateAccelerateInterpolator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| class DecelerateAccelerateInterpolator : TimeInterpolator { override fun getInterpolation(input: Float): Float { var result: Float = 0.0f if (input <= 0.5) { result = Math.sin(Math.PI * input).toFloat() / 2 } else { result= (2 - Math.sin(Math.PI * input)).toFloat() / 2 } return result } }
|
InterpolatorActivity
1 2 3 4 5 6
| val curTranslationX = bt_anim_interpolator.translationX
val animator = ObjectAnimator.ofFloat(bt_anim_interpolator, "translationX", curTranslationX, 300f, curTranslationX) animator.duration = 5000 animator.interpolator = DecelerateAccelerateInterpolator() animator.start()
|
ObjectAnimator与 ValueAnimator类的区别
ValueAnimator 类是先改变值,然后 手动赋值 给对象的属性从而实现动画;是 间接 对对象属性进行操作;
ObjectAnimator 类是先改变值,然后 自动赋值 给对象的属性从而实现动画;是 直接 对对象属性进行操作
估值器(TypeEvaluator) 和插值器
- 插值器(
Interpolator)决定 值 的变化模式(匀速、加速)
- 估值器(
TypeEvaluator)决定 值 的具体变化数值,设置动画从初始值过渡到结束值的逻辑。
https://blog.csdn.net/carson_ho/article/details/99619871
作者:Carson_Ho
链接:https://www.jianshu.com/p/7c95342f4bc2
https://www.jianshu.com/p/2f19fe1e3ca1
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。