編輯:關於Android編程
在今天的文章開始之前,有個忙想請大家幫一下,希望在京東、淘寶、當當、亞馬遜購買了我的書《Android群英傳:神兵利器》的朋友們,幫忙去網店上給個簡短的評價,舉手之勞,還是多謝大家啦~~
通過屬性動畫,我們可以模擬各種屬性的動畫效果,但對於這些屬性來說,動畫變化的速率和范圍,是實現一個更加『真實、自然』的動畫的基礎,這兩件事情,就是通過TimeInterpolator與TypeEvaluator來實現的。
TimeInterpolator與TypeEvaluator共同作用在ValueAnimator上,通過復合的方式產生最後的數據,這也就是數學上的『復合函數』,TimeInterpolator控制在何時取值,而TypeEvaluator控制在當前時間點需要取多少值。
由於這裡涉及到兩個變量,所以,這裡我們通常使用『控制變量法』來進行這兩個屬性的研究,因為通常情況下,這兩個屬性的作用效果是殊途同歸的。
首先,我們研究TimeInterpolator,所以,將TypeEvaluator設置為默認,不產生任何修改。
TimeInterpolator,中文常常翻譯成插值器。一個最簡單的屬性動畫,示例如下:
ObjectAnimator animator = ObjectAnimator.ofFloat(mTextView, "translationX", 0, mDistance); animator.setDuration(mDuration); animator.setInterpolator(new BounceInterpolator()); animator.start();
通過setInterpolator方法,可以給Animator設置插值器,默認的插值器是AccelerateDecelerateInterpolator,即加速減速插值器。
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,例如前面我們舉的例子——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就可以實現了,即實現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通常被翻譯成估值器,在理解了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的類型是Number,那麼這種就和TimeInterpolator幾乎可以完全轉化了,他們的目的都是通過提供的參數來完成曲線的繪制,從而實現對動畫運動的控制。而TimeInterpolator只有一個參數,實現起來更加的簡單,所以,大部分時候,我們都通過TimeInterpolator來實現這種運動曲線的模擬,所以,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
本博文講解流程TouchEvent相關事件簡介流程圖分解講解總結與歸納一.TouchEvent相關事件簡介 android TouchEvent相關事件有&nb
觀察者設計模式的定義:定義了對象之間的一對多依賴,這樣一來,當一個對象改變狀態時,它的所有依賴者都會收到通知並自動更新。 面向對象設計原則:為交互對象之間的松耦全設計而努
寫程序的過程中,想法總會不斷地變,有時候會很糾結,到底做哪種效果好,怎麼做好呢? 就比如這個音樂播放器,我原來的想法是把列表頁面跟歌詞頁面放在同一個Activity中的兩
一、前言 最近學習http框架。 目前寫的這個框架暫時只適用於學習之用,實際用於項目之中還需要不斷的優化。 要從服務器或者