Android動畫:手把手帶你深入了解神秘的插值器(Interpolator)


前言

  • 動畫的使用 是 Android 開發中常用的知識
  • 可是動畫的種類繁多、使用復雜,每當需要 采用自定義動畫 實現 復雜的動畫效果時,很多開發者就顯得束手無策
  • Android中 補間動畫 & 屬性動畫實現動畫的原理是:
實現原理

其中,步驟2中的 插值器(Interpolator)和估值器(TypeEvaluator)是實現 復雜動畫效果的關鍵;本文主要講解 將詳細講解 插值器(Interpolator),通過閱讀本文你將能輕松實現復雜的動畫效果

Carson帶你學Android動畫系列文章:
Carson帶你學Android:一份全面&詳細的動畫知識學習攻略
Carson帶你學Android:常見的三種動畫類型
Carson帶你學Android:補間動畫學習教程
Carson帶你學Android:屬性動畫學習教程
Carson帶你學Android:逐幀動畫學習教程
Carson帶你學Android:自定義動畫神器-估值器(含實例教學)
Carson帶你學Android:自定義動畫神器-插值器(含實例教學)


目錄

示意圖

1. 簡介

  • 定義:Android實現動畫效果中的一個輔助接口
  • 作用:設置 屬性值 從初始值過渡到結束值 的變化規律
  1. 如勻速、加速 & 減速 等等
  2. 即確定了 動畫效果變化的模式,如勻速變化、加速變化 等等

2. 應用場景

實現非線性運動的動畫效果。非線性運動是指動畫改變的速率不是一成不變的,如加速、減速運動的動畫效果。


3. 具體使用

插值器在動畫的使用有兩種方式:在XML / Java代碼中設置:

/*
 * 使用方式1:xml
 * 主要是設置插值器屬性 android:interpolator
 */
 <?xml version="1.0" encoding="utf-8"?>
    <scale xmlns:android="http://schemas.android.com/apk/res/android"

        // 通過資源ID設置插值器
        android:interpolator="@android:anim/overshoot_interpolator"
        android:duration="3000"
        android:fromXScale="0.0"
        android:fromYScale="0.0"
        android:pivotX="50%"
        android:pivotY="50%"
        android:toXScale="2"
        android:toYScale="2" />
 >

/*
 * 使用方式2:java
 */
// 步驟1:創建 需要設置動畫的 視圖View
Button mButton = (Button) findViewById(R.id.Button);
// 步驟2:創建透明度動畫的對象 & 設置動畫效果
Animation alphaAnimation = new AlphaAnimation(1,0);
// 步驟3:創建對應的插值器類對象
alphaAnimation.setDuration(3000);
Interpolator overshootInterpolator = new OvershootInterpolator();
// 步驟4:給動畫設置插值器
alphaAnimation.setInterpolator(overshootInterpolator);
// 步驟5:播放動畫
mButton.startAnimation(alphaAnimation);
  • 那么使用插值器時的資源ID是什么呢?即有哪些類型的插值器可供我們使用呢?
  • 插值器分為兩種:Android內置默認 & 自定義,下面我將詳細介紹

4. 系統內置插值器

4.1 類型

Android內置了 9 種內置的插值器實現:

示意圖

4.2 具體使用

  • 當在XML文件設置插值器時,只需傳入對應的插值器資源ID即可
  • 當在Java代碼設置插值器時,只需創建對應的插值器對象即可

系統默認的插值器是AccelerateDecelerateInterpolator,即先加速后減速

4.3 效果圖

效果圖
  • 使用Android內置的插值器能滿足大多數的動畫需求
  • 如果上述9個插值器無法滿足需求,還可以自定義插值器
  • 下面將介紹如何自定義插值器(Interpolator

5. 自定義插值器

5.1 本質

根據動畫的進度(0%-100%)計算出當前屬性值改變的百分比

5.2 實現方式

自定義插值器需要實現Interpolator或TimeInterpolator接口,并復寫getInterpolation()方法

  1. 補間動畫 實現 Interpolator接口;屬性動畫實現TimeInterpolator接口
  2. TimeInterpolator接口是屬性動畫中新增的,用于兼容Interpolator接口,這使得所有過去的Interpolator實現類都可以直接在屬性動畫使用

Interpolator接口和TimeInterpolator接口說明如下:

// Interpolator接口
public interface Interpolator {  

    // 內部只有一個方法:getInterpolation()
     float getInterpolation(float input) {  
        // 參數說明
        // input值值變化范圍是0-1,且隨著動畫進度(0% - 100% )均勻變化
        // 即動畫開始時,input值 = 0;動畫結束時input = 1
        // 而中間的值則是隨著動畫的進度(0% - 100%)在0到1之間均勻增加
        
      ...// 插值器的計算邏輯

      return xxx;
      // 返回的值就是用于估值器繼續計算的fraction值,下面會詳細說明
    }  

// TimeInterpolator接口
// 同上
public interface TimeInterpolator {  
  
    float getInterpolation(float input){
         ...
    };  
}  

從上面可以看出,自定義插值器的關鍵在于:對input值根據動畫的進度(0%-100%)通過邏輯計算從而計算出當前屬性值改變的百分比。先來看兩個已經實現好的系統內置差值器:

  • 勻速插值器:LinearInterpolator
  • 先加速再減速 插值器: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值 = 運算后的值 = 先加速后減速
        // 所以該差值器是先加速再減速的
    }  
}

5.3 實例說明

下面,我將寫一個自定義Interpolator:先減速后加速。

/*
 * 步驟1:根據需求實現Interpolator接口
 * DecelerateAccelerateInterpolator.java
 */
public class DecelerateAccelerateInterpolator implements TimeInterpolator {
    
    @Override
    public float getInterpolation(float input) {
        float result;
        if (input <= 0.5) {
            result = (float) (Math.sin(Math.PI * input)) / 2;
            // 使用正弦函數來實現先減速后加速的功能,邏輯如下:
            // 因為正弦函數初始弧度變化值非常大,剛好和余弦函數是相反的
            // 隨著弧度的增加,正弦函數的變化值也會逐漸變小,這樣也就實現了減速的效果。
            // 當弧度大于π/2之后,整個過程相反了過來,現在正弦函數的弧度變化值非常小,漸漸隨著弧度繼續增加,變化值越來越大,弧度到π時結束,這樣從0過度到π,也就實現了先減速后加速的效果
        } else {
            result = (float) (2 - Math.sin(Math.PI * input)) / 2;
        }
        return result;
        // 返回的result值 = 隨著動畫進度呈先減速后加速的變化趨勢
    }
}

/*
 * 步驟2:設置使用
 * MainActivity.java
 */
 // 1. 創建動畫作用對象:此處以Button為例
 mButton = (Button) findViewById(R.id.Button);

 // 2. 獲得當前按鈕的位置
float curTranslationX = mButton.getTranslationX();

// 3. 創建動畫對象 & 設置動畫
ObjectAnimator animator = ObjectAnimator.ofFloat(mButton, "translationX", curTranslationX, 300,curTranslationX);
// 表示的是:
// 動畫作用對象是mButton
// 動畫作用的對象的屬性是X軸平移
// 動畫效果是:從當前位置平移到 x=1500 再平移到初始位置

// 4. 設置步驟1中設置好的插值器:先減速后加速
animator.setInterpolator(new DecelerateAccelerateInterpolator());

// 5. 啟動動畫
animator.start();

效果圖

差值器.gif

6. 與估值器的區別

估值器和插值器很多人容易混淆,具體區別如下:

示意圖

7. 總結


歡迎關注Carson_Ho的簡書

不定期分享關于安卓開發的干貨,追求短、平、快,但卻不缺深度


請點贊!因為你的鼓勵是我寫作的最大動力!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容