Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> 模擬自然動畫的精髓——TimeInterpolator與TypeEvaluator

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

編輯:關於Android編程

在今天的文章開始之前,有個忙想請大家幫一下,希望在京東、淘寶、當當、亞馬遜購買了我的書《Android群英傳:神兵利器》的朋友們,幫忙去網店上給個簡短的評價,舉手之勞,還是多謝大家啦~~

通過屬性動畫,我們可以模擬各種屬性的動畫效果,但對於這些屬性來說,動畫變化的速率和范圍,是實現一個更加『真實、自然』的動畫的基礎,這兩件事情,就是通過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);
    }
}

其重點就是實現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 {

    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);
    }
}

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;
}

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

自然動畫

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

緩動函數

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

http://easings.net/zh-cn

這裡寫圖片描述

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

http://inloop.github.io/interpolator/

自然動畫的模擬演示

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

這裡寫圖片描述

這裡主要有幾個功能:

可以選擇不同的TimeInterpolator 可以選擇要演示的動畫效果,包括位移、縮放、旋轉、透明度 演示包含兩個View,上面的是設置對應動畫模擬效果的View,下面的是對照的線性效果的View

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

這裡寫圖片描述

代碼已經開源到Github:

https://github.com/xuyisheng/NaturalAnim

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved