模擬自然動畫的精髓——TimeInterpolator與TypeEvaluator

qqww5566 8年前發布 | 10K 次閱讀 安卓開發 Android開發 移動開發

模擬自然動畫的精髓——TimeInterpolator與TypeEvaluator

通過屬性動畫,我們可以模擬各種屬性的動畫效果,但對于這些屬性來說,動畫變化的速率和范圍,是實現一個更加『真實、自然』的動畫的基礎,這兩件事情,就是通過TimeInterpolator與TypeEvaluator來實現的。

TimeInterpolator與TypeEvaluator共同作用在ValueAnimator上,通過復合的方式產生最后的數據,這也就是數學上的『復合函數』,TimeInterpolator控制在何時取值,而TypeEvaluator控制在當前時間點需要取多少值。

由于這里涉及到兩個變量,所以,這里我們通常使用『控制變量法』來進行這兩個屬性的研究,因為通常情況下,這兩個屬性的作用效果是殊途同歸的。

TimeInterpolator

首先,我們研究TimeInterpolator,所以,將TypeEvaluator設置為默認,不產生任何修改。

TimeInterpolator,中文常常翻譯成插值器。一個最簡單的屬性動畫,示例如下:

ObjectAnimator animator = ObjectAnimator.ofFloat(mTextView, "translationX", 0, mDistance);
animator.setDuration(mDuration);
animator.setInterpolator(new BounceInterpolator());
animator.start();

通過setInterpolator方法,可以給Animator設置插值器,默認的插值器是AccelerateDecelerateInterpolator,即加速減速插值器。

理解TimeInterpolator的作用原理

TimeInterpolator是作用在時間參數上,例如我們有一個動畫,時間從0到1,取值也從0到1,我們通過下面三條曲線來看同一時間點,取到的數值的不同。

當時間取0.5時,我們對應的y=x這條曲線,取出的是0.5,y=sqrt(x)這條曲線,取出的是0.25,y=x^2 這條曲線,取出的是0.7。也就是說,同一個真實的時間節點0.5,我們通過設置不同的函數曲線,取出了不同的數值,那么TimeInterpolator正是通過這種方式,來對時間參數進行修改,即,真實的時間0.5,對于其它兩個函數,分別取出了模擬時間0.25和0.7所對應的值,從而達到了『篡改』時間的目的。

Android中的TimeInterpolator

Android中已經給我們實現了很多TimeInterpolator,例如前面我們舉的例子——AccelerateDecelerateInterpolator。我們打開AccelerateDecelerateInterpolator的源碼。

其中關鍵的就是那行數學公式——(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f。我們來繪制下這個公式對應的曲線圖(這里input的取值范圍是0到1)。

在[0,1]區間內,就是我們的加速減速插值器了,結合字面意義很好理解。

那么在Android中,系統還給我們提供了非常多的TimeInterpolator,例如:AccelerateDecelerateInterpolator, AccelerateInterpolator, AnticipateInterpolator, AnticipateOvershootInterpolator, BounceInterpolator, CycleInterpolator, DecelerateInterpolator, LinearInterpolator, OvershootInterpolator, PathInterpolator。

大家可以通過API文檔來找到這些插值器的定義,同時,通過源碼來查看他們使用的數學公式。

自定義TimeInterpolator

自定義TimeInterpolator非常簡單,我們參考系統自帶的TimeInterpolator就可以實現了,即實現Interpolator接口和getInterpolation方法即可,例如:

package com.xys.naturalanim.views.interpolator;

import android.view.animation.Interpolator;

public class CustomInterpolator implements Interpolator {

@Override
public float getInterpolation(float input) {
    return (float) Math.sin((input) * Math.PI * 0.5F);
}

}</code></pre>

其重點就是實現getInterpolation方法中的數學公式。

TypeEvaluator

TypeEvaluator通常被翻譯成估值器,在理解了TimeInterpolator之后,再理解TypeEvaluator就很簡單了,一個系統自帶的簡單TypeEvaluator如下:

可見,它和TimeInterpolator基本一樣,只不過實現的公式的參數不一樣,但簡單的換算一下,就通用了,例如:

if (mInterpolator != null) {
    for (int i = 0; i < mViewWidth; i++) {
        mPath.lineTo(i, mViewHeight - mInterpolator.getInterpolation(i * 1.0F / mViewHeight) * mViewHeight);
    }
} else {
    for (int i = 0; i < mViewWidth; i++) {
        mPath.lineTo(i, mViewHeight - (Integer) mTypeEvaluator.evaluate(i * 1.0F / mViewHeight, 0, mViewHeight));
    }
}

但是它們還是有一些細小的區別的,后面再細說,簡單的概括,就是:

TimeInterpolator控制動畫的速度,而TypeEvaluator控制動畫的值,他們可以共同作用,也可以單獨作用(讓另一個使用默認值)。

實際上,TypeEvaluator中的一個參數fraction,就是『復合函數』中TimeInterpolator計算的結果。即fraction=getInterpolation()。

自定義TypeEvaluator

這里首先講一下TypeEvaluator的自定義,那么為什么要加呢,這是因為,這種方式限定了TypeEvaluator的類型是Number,那么這種就和TimeInterpolator幾乎可以完全轉化了,他們的目的都是通過提供的參數來完成曲線的繪制,從而實現對動畫運動的控制。而TimeInterpolator只有一個參數,實現起來更加的簡單,所以,大部分時候,我們都通過TimeInterpolator來實現這種運動曲線的模擬,所以,TypeEvaluator就這樣沒落了。

但是,不要以為TypeEvaluator就這樣沒用了,我們在小標題中也寫了,是類型的TypeEvaluator可以進行轉換,而TypeEvaluator實際上還有很多其它類型,在動畫的坐標控制上,有奇效。

TypeEvaluator控制點的坐標

前面我們說了,Float類型的TypeEvaluator和TimeInterpolator基本是一樣的,但TypeEvaluator并不只有Float這樣一種,它有一種用的比較多的特性,就是通過TypeEvaluator來對運動坐標進行修改,將原本的直線坐標修改成曲線坐標,它通常會與ValueAnimator進行配合使用,例如下面的這個例子:

這種實現曲線運動的方式,就是通過TypeEvaluator來進行實現的,其中核心原理,就是通過Bezier曲線的De Casteljau算法計算出具體的點坐標,并設置給TypeEvaluator,代碼如下所示。

public class BezierEvaluator implements TypeEvaluator<PointF> {

private PointF mControlPoint;

public BezierEvaluator(PointF controlPoint) {
    this.mControlPoint = controlPoint;
}

@Override
public PointF evaluate(float t, PointF startValue, PointF endValue) {
    return BezierUtil.CalculateBezierPointForQuadratic(t, startValue, mControlPoint, endValue);
}

}</code></pre>

Bezier的計算公式如下所示。

/**

  • B(t) = (1 - t)^2 P0 + 2t (1 - t) P1 + t^2 P2, t ∈ [0,1] *
  • @param t 曲線長度比例
  • @param p0 起始點
  • @param p1 控制點
  • @param p2 終止點
  • @return t對應的點 / public static PointF CalculateBezierPointForQuadratic(float t, PointF p0, PointF p1, PointF p2) { PointF point = new PointF(); float temp = 1 - t; point.x = temp temp p0.x + 2 t temp p1.x + t t p2.x; point.y = temp temp p0.y + 2 t temp p1.y + t t * p2.y; return point; }</code></pre>

    所以,綜上所述,在作動畫速率曲線控制的時候,使用TimeInterpolator即可,如果要改變點的坐標,就可以使用TypeEvaluator。

    自然動畫

    在了解了TimeInterpolator和TypeEvaluator之后,我們就可以來了解下動畫展現的優化方式了,普通的動畫默認以線性的方式展現,但帶來的后果就是動畫效果的『僵硬』,動畫本來是模擬兩個狀態的過渡過程的,這個在自然界中是『自然、流暢』的,所以,我們不能通過線性的數據變化來模擬自然動畫,這就需要使用TimeInterpolator和TypeEvaluator來設計動畫曲線了,通過它們來控制動畫的實現過程,從而實現動畫的展示,這就是我們來實現自然動畫的的基本方式。

    緩動函數

    既然線性的動畫曲線無法滿足我們的動畫模擬需求,那么就需要通過一定的數學公式來改變這些動畫曲線,值得慶幸的是,這些事情有人幫我們做過了,有人專門設計了這樣一些動畫的曲線庫。

    http://easings.net/zh-cn

    就是這樣一些緩動函數庫,讓我們在設計動畫的時候,可以作更加真實的模擬。同時,你也可以設計自己的曲線函數,下面這個網站,就可以實現這樣的模擬。

    自然動畫的模擬演示

    在各位前輩的肩膀上,我這里擼了一個演示的Demo庫,界面如圖。

    這里主要有幾個功能:

    • 可以選擇不同的TimeInterpolator

    • 可以選擇要演示的動畫效果,包括位移、縮放、旋轉、透明度

    • 演示包含兩個View,上面的是設置對應動畫模擬效果的View,下面的是對照的線性效果的View

    一個動態圖簡單的了解下:

     

     

     

     

 本文由用戶 qqww5566 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!