安全Android开发经验谈

Android动画中篇(插值器、估值器)

2018-11-03  本文已影响0人  luoqiang108

插值器(Interpolator)&估值器(TypeEvaluator)

插值器(Interpolator)

非线性运动:动画改变的速率不是一成不变的,如加速 & 减速运动都属于非线性运动

  1. 在动画效果的XML代码中设置插值器属性android:interpolator
<?xml version="1.0" encoding="utf-8"?>
<!--通过资源ID设置插值器-->
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/overshoot_interpolator"
    android:duration="3000"
    android:startOffset="1000"

    android:fromXScale="0.0"
    android:toXScale="2"
    android:fromYScale="0.0"
    android:toYScale="2"
    android:pivotX="50%"
    android:pivotY="50%">
</scale>
  1. 在 Java 代码中设置
Animation scaleAnimation = new ScaleAnimation(0, 2, 0, 2, Animation.RELATIVE_TO_SELF, 0.5f, Animation.RELATIVE_TO_SELF, 0.5f);
scaleAnimation.setDuration(3000);
//scaleAnimation.setInterpolator(MainActivity.this,android.R.anim.overshoot_interpolator); 通过设置资源ID方式实现,等同于下面创建对象方式
//创建对应的插值器类对象
Interpolator overShootInterpolator = new OvershootInterpolator();
//给动画设置插值器
scaleAnimation.setInterpolator(overShootInterpolator);
//播放动画
button.startAnimation(scaleAnimation);
作用 资源ID 对应的Java类
动画加速进行 @android:anim/accelerate_interpolator AccelerateInterpolator
快速完成动画,超出再回到结束样式 @android:anim/overshoot_interpolator OvershootInterpolator
先加速再减速 @android:anim/accelerate_decelerate_interpolator AccelerateDecelerateInterpolator
先退后再加速前进 @android:anim/anticipate_interpolator AnticipateInterpolator
先退后再加速前进,超出终点后再回终点 @android:anim/anticipate_overshoot_interpolator AnticipateOvershootInterpolator
最后阶段弹球效果 @android:anim/bounce_interpolator BounceInterpolator
周期运动 @android:anim/cycle_interpolator CycleInterpolator
减速 @android:anim/decelerate_interpolator DecelerateInterpolator
匀速 @android:anim/linear_interpolator LinearInterpolator

系统默认的插值器是AccelerateDecelerateInterpolator,即先加速后减速

自定义插值器
  1. 补间动画实现Interpolator接口;属性动画一般实现TimeInterpolator接口
  2. TimeInterpolator接口是属性动画中新增的,用于兼容Interpolator接口,这使得所有过去的Interpolator实现类也可以直接在属性动画使用。
// Interpolator接口
public interface Interpolator {  
     // 内部只有一个方法
     /*参数说明:
     input值值变化范围是0-1,且随着动画进度(0% - 100% )均匀变化;
     即动画开始时,input值 = 0,动画结束时input = 1;
     而中间的值则是随着动画的进度(0% - 100%)在0到1之间均匀增加。*/
     float getInterpolation(float input) {  
      ...// 插值器的计算逻辑
      // 返回的值就是用于估值器继续计算的fraction值,下面会详细说明
      return xxx;
}  

// TimeInterpolator接口
// 同上
public interface TimeInterpolator {   
    float getInterpolation(float input);     
}
  1. 匀速插值器:LinearInterpolator
  2. 先加速再减速 插值器:AccelerateDecelerateInterpolator
// 匀速差值器:LinearInterpolator
    @HasNativeInterpolator
    public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
        // 仅贴出关键代码
        ...
        public float getInterpolation(float input) {
            return input;
            /*没有对input值进行任何逻辑处理,直接返回
             即input值 = fraction值
             因为input值是匀速增加的,因此fraction值也是匀速增加的,
             所以动画的运动情况也是匀速的,所以是匀速插值器。*/
        }
    }

    // 先加速再减速 差值器:AccelerateDecelerateInterpolator
    @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的运算逻辑如下:
             使用了余弦函数,因input的取值范围是0到1,那么cos函数中的取值范围就是π到2π。
             而cos(π)的结果是-1,cos(2π)的结果是1
             所以该值除以2加上0.5后,getInterpolation()方法最终返回的结果值还是在0到1之间。
             只不过经过了余弦运算之后,最终的结果不再是匀速增加的了,而是经历了一个先加速后减速的过程
             所以最终,fraction值 = 运算后的值 = 先加速后减速,所以该差值器是先加速再减速的。*/
        }
    }
实例
  1. 根据需求实现Interpolator接口
    DecelerateAccelerateInterpolator.java
package cn.lq.com.blog;

import android.animation.TimeInterpolator;

public class DecelerateAccelerateInterpolator implements TimeInterpolator {
    @Override
    public float getInterpolation(float input) {
        float result;
        if (input <= 0.5) {
            // 使用正弦函数来实现先减速后加速的功能,逻辑如下:
            // 因为正弦函数初始弧度变化值非常大,刚好和余弦函数是相反的
            // 随着弧度的增加,正弦函数的变化值也会逐渐变小,这样也就实现了减速的效果。
            // 当弧度大于π/2之后,整个过程相反了过来,现在正弦函数的弧度变化值非常小,渐渐随着弧度继续增加,变化值越来越大,弧度到π时结束,这样从0过度到π,也就实现了先减速后加速的效果
            result = (float) (Math.sin(Math.PI * input)) / 2;
        } else {
            result = (float) (2 - Math.sin(Math.PI * input)) / 2;
        }
        // 返回的result值 = 随着动画进度呈先减速后加速的变化趋势
        return result;
    }
}
  1. 创建自定义Interpolator对象并使用
                // 获得当前按钮的位置
                float curTranslationX = button.getTranslationX();
                // 创建对象属性动画,后面会详细说明。
                /*参数表示的意思是:
                动画作用对象是button
                动画作用的对象的属性是X轴平移
                动画效果是:从当前位置平移到x=500的位置再平移到初始位置*/
                ObjectAnimator animator = ObjectAnimator.ofFloat(button, "translationX", curTranslationX, 500, curTranslationX);
                animator.setDuration(3000);
                //创建自定义插值器类对象
                TimeInterpolator decelerateAccelerateInterpolator = new DecelerateAccelerateInterpolator();
                //给动画设置自定义插值器
                animator.setInterpolator(decelerateAccelerateInterpolator);
                //播放动画
                animator.start();
效果图 自定义插值器.gif

估值器(TypeEvaluator)

  1. 插值器(Interpolator)决定值的变化规律(匀速、加速等等),即决定的是变化趋势;而估值器决定数值的具体变化。
  2. 属性动画特有的属性。
// 在第4个参数中传入对应估值器类的对象
ObjectAnimator anim = ObjectAnimator.ofObject(button, "height", new Evaluator(),1,3);

IntEvaluator:以整型的形式从初始值 - 结束值 进行过渡
FloatEvaluator:以浮点型的形式从初始值 - 结束值 进行过渡
ArgbEvaluator:以Argb类型的形式从初始值 - 结束值 进行过渡

自定义估值器

如:动画进行了50%(初始值=100,结束值=200 ),那么匀速插值器计算出了当前属性值改变的百分比是50%,那么估值器则负责计算当前属性值 = 100 + (200-100)x50% = 150。

public interface TypeEvaluator {  
    // 参数说明
    // fraction:插值器getInterpolation()方法的返回值
    // startValue:动画的初始值
    // endValue:动画的结束值
    public Object evaluate(float fraction, Object startValue, Object endValue) {  
        ....// 估值器的计算逻辑
        return xxx;
        // 赋给动画属性具体数值,使用反射机制改变属性变化
    }  
}

特别注意:
插值器的input值和估值器fraction有什么关系呢?
答:input的值决定了fraction的值,input值经过计算后传入到插值器的getInterpolation()方法,然后通过实现getInterpolation()方法中的逻辑算法,根据input值来计算出一个返回值,而这个返回值就是fraction了。

// FloatEvaluator实现了TypeEvaluator接口
public class FloatEvaluator implements TypeEvaluator {  
    // 重写evaluate()
    // 参数说明
    // fraction:表示动画完成度(根据它来计算当前动画的值)
    // startValue、endValue:动画的初始值和结束值
    public Object evaluate(float fraction, Object startValue, Object endValue) {  
        float startFloat = ((Number) startValue).floatValue();  
        return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);  
        // 初始值过渡到结束值的算法是:
        // 1. 用结束值减去初始值,算出它们之间的差值
        // 2. 用上述差值乘以fraction系数
        // 3. 再加上初始值,就得到当前动画的值
    }  
}
// 实现TypeEvaluator接口
public class ObjectEvaluator implements TypeEvaluator{  
    // 复写evaluate()
    // 在evaluate()里写入对象动画过渡的逻辑
    @Override  
    public Object evaluate(float fraction, Object startValue, Object endValue) {  
        // 参数说明
        // fraction:表示动画完成度(根据它来计算当前动画的值)
        // startValue、endValue:动画的初始值和结束值
        ... // 写入对象动画过渡的逻辑
        // 返回对象动画过渡的逻辑计算后的值
        return value;  
    }

感谢

Android 动画:你真的会使用插值器与估值器吗?(含详细实例教学)

上一篇 下一篇

猜你喜欢

热点阅读