動畫:Interpolator插值器使用和自定義詳解
前言
屬性動畫可以對某個屬性做動畫,而插值器(TimeInterpolator)和估值器(TypeEvaluator)在其中扮演了重要角色;
那么今天我們了解下 插值器TimeInterpolator;
一、插值器介紹
1、Interpolator有什么用
- Interpolator 被用來修飾動畫效果,定義動畫的變化率;
- 在Android源碼中對應的接口類為TimeInterpolator,通過輸入均勻變化的0~1之間的值;
- 可以得到勻速、正加速、負加速、無規(guī)則變加速等0~1之間的變化曲線;
2、應用場景
- 實現(xiàn)非線性運動的動畫效果;
- 非線性運動是指動畫改變的速率不是一成不變的,如加速、減速運動的動畫效果;
- 實現(xiàn)復雜的曲線動畫,回彈效果自定義等都需要自定義插值器;
3、Android系統(tǒng)提供的插值器類型
- AccelerateDecelerateInterpolator 在動畫開始與結(jié)束比較慢,中間加速
- AccelerateInterpolator 加速
- AnticipateInterpolator 開始的時候向后然后向前甩
- AnticipateOvershootInterpolator 開始的時候向后然后向前甩一定值后返回最后的值
- BounceInterpolator 動畫結(jié)束的時候彈起
- CycleInterpolator 動畫循環(huán)播放特定的次數(shù),速率改變沿著正弦曲線
- DecelerateInterpolator 減速
- LinearInterpolator 以常量速率改變
- OvershootInterpolator 向前甩一定值后再回到原來位置
二、插值器應用
插值器的使用有兩種方式:在XML和代碼中使用
1、xml
XML動畫文件使用插值器時,需要設置系統(tǒng)設置的對應的插值器資源ID
- <?xml version="1.0" encoding="utf-8"?>
- <set xmlns:android="http://schemas.android.com/apk/res/android">
- <alpha
- android:fromAlpha="1.0"
- android:toAlpha="0.1"
- android:duration="2000"
- android:repeatMode="reverse"
- android:repeatCount="infinite"
- android:interpolator="@android:anim/linear_interpolator"/>
- </set>
2、代碼中使用
- 代碼使用插值器時,只需創(chuàng)建對應的插值器對象,然后設置給動畫對象;也可以加載xml文件中配置的插值器;
- 利用view的setInterpolator(Context context, @AnimRes @InterpolatorRes int resID)設置插值器;
- //創(chuàng)建一個漸變透明度的動畫,從透明到完全不透明
- AlphaAnimation alphaAnimation = new AlphaAnimation(0.1f, 1.0f);
- //設置動畫時長
- alphaAnimation.setDuration(5000);
- //設置動畫重復方式
- alphaAnimation.setRepeatMode(AlphaAnimation.REVERSE);
- //設置動畫播放次數(shù)
- alphaAnimation.setRepeatCount(AlphaAnimation.INFINITE);
- //設置勻速插值器
- alphaAnimation.setInterpolator(new LinearInterpolator());
- //為View開啟指定類型動畫
- imageView.startAnimation(alphaAnimation)
- 使用Android內(nèi)置的插值器能滿足大多數(shù)的動畫需求;
- 如果系統(tǒng)提供的插值器無法滿足需求,還可以自定義插值器;
三、自定義插值器
1、實現(xiàn)方式
- 自定義插值器需要實現(xiàn)Interpolator或TimeInterpolator接口,并復寫getInterpolation()方法;
- 補間動畫 實現(xiàn) Interpolator接口;屬性動畫實現(xiàn)TimeInterpolator接口;
- TimeInterpolator接口是屬性動畫中新增的,用于兼容Interpolator接口,這使得所有過去的Interpolator實現(xiàn)類都可以直接在屬性動畫使用;
Interpolator接口和TimeInterpolator接口說明如下:
- // Interpolator接口
- public interface Interpolator {
- // 內(nèi)部只有一個方法:getInterpolation()
- float getInterpolation(float input) {
- // 參數(shù)說明
- // input值值變化范圍是0-1,且隨著動畫進度(0% - 100% )均勻變化
- // 即動畫開始時,input值 = 0;動畫結(jié)束時input = 1
- // 而中間的值則是隨著動畫的進度(0% - 100%)在0到1之間均勻增加
- ...// 插值器的計算邏輯
- return xxx;
- // 返回的值就是用于估值器繼續(xù)計算的fraction值,下面會詳細說明
- }
- // TimeInterpolator接口
- public interface TimeInterpolator {
- float getInterpolation(float input){
- // input值值變化范圍是0-1,且隨著動畫進度(0% - 100% )均勻變化
- ...// 插值器的計算邏輯
- };
- }
自定義插值器的關(guān)鍵在于:對input值根據(jù)動畫的進度(0%-100%)通過邏輯計算從而計算出當前屬性值改變的百分比;
2、自定義插值器
寫一個自定義Interpolator:先減速后加速
- /*
- * 根據(jù)需求實現(xiàn)Interpolator接口
- * TestInterpolator.java
- */
- public class TestInterpolator implements TimeInterpolator {
- @Override
- public float getInterpolation(float input) {
- float result;
- if (input <= 0.5) {
- result = (float) (Math.sin(Math.PI * input)) / 2;
- // 使用正弦函數(shù)來實現(xiàn)先減速后加速的功能,邏輯如下:
- // 因為正弦函數(shù)初始弧度變化值非常大,剛好和余弦函數(shù)是相反的
- // 隨著弧度的增加,正弦函數(shù)的變化值也會逐漸變小,這樣也就實現(xiàn)了減速的效果。
- // 當弧度大于π/2之后,整個過程相反了過來,現(xiàn)在正弦函數(shù)的弧度變化值非常小,漸漸隨著弧度繼續(xù)增加,變化值越來越大,弧度到π時結(jié)束,這樣從0過度到π,也就實現(xiàn)了先減速后加速的效果
- } else {
- result = (float) (2 - Math.sin(Math.PI * input)) / 2;
- }
- return result;
- // 返回的result值 = 隨著動畫進度呈先減速后加速的變化趨勢
- }
- }
- /*
- * 步驟設置使用
- * Test.java
- */
- // 創(chuàng)建動畫作用對象:此處以Button為例
- mButton = (Button) findViewById(R.id.Button);
- // 獲得當前按鈕的位置
- float curTranslationX = mButton.getTranslationX();
- // 創(chuàng)建動畫對象 & 設置動畫
- ObjectAnimator animator = ObjectAnimator.ofFloat(mButton, "translationX", curTranslationX, 300,curTranslationX);
- // 表示的是:
- // 動畫作用對象是mButton
- // 動畫作用的對象的屬性是X軸平移
- // 動畫效果是:從當前位置平移到 x=1500 再平移到初始位置
- // 設置步驟1中設置好的插值器:先減速后加速
- animator.setInterpolator(new TestInterpolator());
- // 啟動動畫
- animator.start();
3、貝塞爾曲線的插值器
(1)先使用貝塞爾曲線數(shù)值生成工具來獲取想要的曲線數(shù)值
- 工具網(wǎng)站:https://cubic-bezier.com/;
- 拉拽左邊圖像的2個點,調(diào)整出符合效果的圖形;
- 點擊Go按鍵,可看到紅色與藍色的方塊運動狀態(tài),調(diào)節(jié)自己想要的效果;
- 將4個參數(shù)運用到下面的代碼中;
(2)代碼運用
- ObjectAnimator animator = ObjectAnimator.ofFloat(mButton, "translationX", curTranslationX, 300,curTranslationX);
- EaseCubicInterpolator interpolator = new EaseCubicInterpolator(0.31f, 0.85f,0.77f, 0.14f);
- animator.setInterpolator(interpolator)
(3)貝塞爾曲線插值器
- import android.graphics.PointF;
- import android.view.animation.Interpolator;
- /**
- * 緩動三次方曲線插值器.(基于三次方貝塞爾曲線)
- */
- public class EaseCubicInterpolator implements Interpolator {
- private final static int ACCURACY = 4096;
- private int mLastI = 0;
- private final PointF mControlPoint1 = new PointF();
- private final PointF mControlPoint2 = new PointF();
- /**
- * 設置中間兩個控制點
- *
- * 在線工具: http://cubic-bezier.com
- *
- * @param x1
- * @param y1
- * @param x2
- * @param y2
- */
- public EaseCubicInterpolator(float x1, float y1, float x2, float y2) {
- mControlPoint1.x = x1;
- mControlPoint1.y = y1;
- mControlPoint2.x = x2;
- mControlPoint2.y = y2;
- }
- @Override
- public float getInterpolation(float input) {
- float t = input;
- // 近似求解t的值[0,1]
- for (int i = mLastI; i < ACCURACY; i++) {
- t = 1.0f * i / ACCURACY;
- double x = cubicCurves(t, 0, mControlPoint1.x, mControlPoint2.x, 1);
- if (x >= input) {
- mLastI = i;
- break;
- }
- }
- double value = cubicCurves(t, 0, mControlPoint1.y, mControlPoint2.y, 1);
- if (value > 0.999d) {
- value = 1;
- mLastI = 0;
- }
- return (float) value;
- }
- /**
- * 求三次貝塞爾曲線(四個控制點)一個點某個維度的值.<br>
- * <p>
- *
- * @param t 取值[0, 1]
- * @param value0
- * @param value1
- * @param value2
- * @param value3
- * @return
- */
- public static double cubicCurves(double t, double value0, double value1,
- double value2, double value3) {
- double value;
- double u = 1 - t;
- double tt = t * t;
- double uu = u * u;
- double uuu = uu * u;
- double ttt = tt * t;
- value = uuu * value0;
- value += 3 * uu * t * value1;
- value += 3 * u * tt * value2;
- value += ttt * value3;
- return value;
- }
- }
總結(jié)
要實現(xiàn)復雜的動畫效果時,就要自定義插值器,其實插值器還是的學習算法;
大家一起加油;