滲透理解Animation時間插值Interpolator類

========================================================
作者:qiujuer
博客:blog.csdn.net/qiujuer
網站:www.qiujuer.net
開源庫:Genius-Android
轉載請註明出處:http://blog.csdn.net/qiujuer/article/details/42430269
========================================================

  • 一個好的動畫一定是用心做出來的,何爲用心?其中一點我認爲定義適當的 Interpolator 就是一種用心的表現;這點在 google material design 中尤爲明顯。
  • 一個好的動畫一定要符合實際,一句老的話就是:石頭下落一定要受重力才優雅,不然一顆石頭像羽毛一樣在風中還飄啊飄的那就不行了。

介紹

Interpolator 是個什麼東西?

說到 Interpolator 啊,這個要從3年前說起,話說當年谷歌、諾基亞、Qiujuer 三分天下.... 哈哈,開個玩笑~

Interpolator 這個時間插值類,其主要使用在動畫中,其作用主要是控制目標變量的變化值進行對應的變化。

你可以這麼理解,現在小明去買醬油,規定時間是1個小時到達,里程是1公里;現在小明心裏唯恐無法達到,所以先跑起來了,但因爲體力消耗所以逐漸的慢下來了;然後成功到達。這樣的一個過程中把小明逐漸慢下來的這個過程抽象出來也就是 Interpolator  的工作;當然 Interpolator 也可以控制小明先慢慢熱身然後越跑越快最後達到。

這些都是 Interpolator 能完成的工作,同樣 Interpolator 還能控制一個彈球掉在地上彈起來逐漸降低的過程,這些都是可以控制的。

Interpolator 的原理?

public interface Interpolator extends TimeInterpolator {
}
可以看見這個類其是是一個空的類,那麼其操作在哪裏?

/**
 * A time interpolator defines the rate of change of an animation. This allows animations
 * to have non-linear motion, such as acceleration and deceleration.
 */
public interface TimeInterpolator {

    /**
     * Maps a value representing the elapsed fraction of an animation to a value that represents
     * the interpolated fraction. This interpolated value is then multiplied by the change in
     * value of an animation to derive the animated value at the current elapsed animation time.
     *
     * @param input A value between 0 and 1.0 indicating our current point
     *        in the animation where 0 represents the start and 1.0 represents
     *        the end
     * @return The interpolation value. This value can be more than 1.0 for
     *         interpolators which overshoot their targets, or less than 0 for
     *         interpolators that undershoot their targets.
     */
    float getInterpolation(float input);
}
其操作在所繼承的接口中,在所繼承的接口中有一個方法 float getInterpolation(float input);

在這個方法中,傳入的值是一個0.0~1.0的值,返回值可以小於0.0也可以大於1.0。

你可以這麼理解:在Animation中時間是正常的走的,你設置了200ms,現在走到了100ms了,那麼按照線性來說現在應該是走了一半的路程也就是0.5;現在就把這0.5傳遞給Interpolator 讓 Interpolator 告訴我走到一半時間的時候此時小明在哪裏;這也就是 Interpolator 的原理。

常用類

哎呀我的天天啊,訪問不了谷歌就是麻煩,只能從源碼截圖了:


Android 官方提供的就是這麼十種,是9種還是10種啊,沒有數錯吧。分別是:

  1. AccelerateDecelerateInterpolator 在動畫開始與結束的地方速率改變比較慢,在中間的時候加速
  2. AccelerateInterpolator  在動畫開始的地方速率改變比較慢,然後開始加速   
  3. AnticipateInterpolator 開始的時候向後然後向前甩
  4. AnticipateOvershootInterpolator 開始的時候向後然後向前甩一定值後返回最後的值
  5. BounceInterpolator   動畫結束的時候彈起
  6. CycleInterpolator 動畫循環播放特定的次數,速率改變沿着正弦曲線
  7. DecelerateInterpolator 在動畫開始的地方快然後慢
  8. LinearInterpolator   以常量速率改變
  9. OvershootInterpolator    向前甩一定值後再回到原來位置
  10. PathInterpolator 這個是新增的我說原來怎麼記得是9個,這個顧名思義就是可以定義路徑座標,然後可以按照路徑座標來跑動;注意其座標並不是 XY,而是單方向,也就是我可以從0~1,然後彈回0.5 然後又彈到0.7 有到0.3,直到最後時間結束。(這個後面單獨說說)

源碼

這裏說幾個簡單的源碼

LinearInterpolator

@HasNativeInterpolator
public class LinearInterpolator implements Interpolator, NativeInterpolatorFactory {

    public LinearInterpolator() {
    }
    
    public LinearInterpolator(Context context, AttributeSet attrs) {
    }
    
    public float getInterpolation(float input) {
        return input;
    }

    /** @hide */
    @Override
    public long createNativeInterpolator() {
        return NativeInterpolatorFactoryHelper.createLinearInterpolator();
    }
}
最簡單的一個由於是線性,所以直接返回。

DecelerateInterpolator

public class DecelerateInterpolator implements Interpolator, NativeInterpolatorFactory {
    public DecelerateInterpolator() {
    }

    /**
     * Constructor
     *
     * @param factor Degree to which the animation should be eased. Setting factor to 1.0f produces
     *        an upside-down y=x^2 parabola. Increasing factor above 1.0f makes exaggerates the
     *        ease-out effect (i.e., it starts even faster and ends evens slower)
     */
    public DecelerateInterpolator(float factor) {
        mFactor = factor;
    }

    public DecelerateInterpolator(Context context, AttributeSet attrs) {
        this(context.getResources(), context.getTheme(), attrs);
    }

    /** @hide */
    public DecelerateInterpolator(Resources res, Theme theme, AttributeSet attrs) {
        TypedArray a;
        if (theme != null) {
            a = theme.obtainStyledAttributes(attrs, R.styleable.DecelerateInterpolator, 0, 0);
        } else {
            a = res.obtainAttributes(attrs, R.styleable.DecelerateInterpolator);
        }

        mFactor = a.getFloat(R.styleable.DecelerateInterpolator_factor, 1.0f);

        a.recycle();
    }

    public float getInterpolation(float input) {
        float result;
        if (mFactor == 1.0f) {
            result = (float)(1.0f - (1.0f - input) * (1.0f - input));
        } else {
            result = (float)(1.0f - Math.pow((1.0f - input), 2 * mFactor));
        }
        return result;
    }

    private float mFactor = 1.0f;

    /** @hide */
    @Override
    public long createNativeInterpolator() {
        return NativeInterpolatorFactoryHelper.createDecelerateInterpolator(mFactor);
    }
}
從其中可以看出,其並不是一個簡單的類,其是是可以通過 XML 進行設置的類,通過 XML 可以設置其中的 mFactor 變量,其值默認是1.0;值越大其變化越快;得到的結果就是,開始的時候更加的快,其結果就是更加的慢,好比一個人開始跑的很快,但是換來的就是後面的路程將會花更多時間慢慢走。

在方法

    public float getInterpolation(float input) {
        float result;
        if (mFactor == 1.0f) {
            result = (float)(1.0f - (1.0f - input) * (1.0f - input));
        } else {
            result = (float)(1.0f - Math.pow((1.0f - input), 2 * mFactor));
        }
        return result;
    }
其描述的是一個初中學的拋物方程(話說是初中吧),y = x^2 我擦不知道怎麼弄上去,就這樣吧;意思懂就OK。

由於篇幅就說這麼兩個;下面說說其他東西。

動畫表


這個圖片相信前段時間看的不少吧?前段時間 material design 剛剛出來的時候好多人說這個啊,但是好像都是說圖,但是沒有說說其如何實現吧。

實現

這裏送上福利,其是最開始我發現的是 C++ 的版本:

float Elastic::easeIn (float t,float b , float c, float d) {
 if (t==0) return b;  if ((t/=d)==1) return b+c;  
 float p=d*.3f;
 float a=c; 
 float s=p/4;
 float postFix =a*pow(2,10*(t-=1)); // this is a fix, again, with post-increment operators
 return -(postFix * sin((t*d-s)*(2*PI)/p )) + b;
}
 
float Elastic::easeOut(float t,float b , float c, float d) {
 if (t==0) return b;  if ((t/=d)==1) return b+c;  
 float p=d*.3f;
 float a=c; 
 float s=p/4;
 return (a*pow(2,-10*t) * sin( (t*d-s)*(2*PI)/p ) + c + b); 
}
 
float Elastic::easeInOut(float t,float b , float c, float d) {
 if (t==0) return b;  if ((t/=d/2)==2) return b+c; 
 float p=d*(.3f*1.5f);
 float a=c; 
 float s=p/4;
 
 if (t < 1) {
 float postFix =a*pow(2,10*(t-=1)); // postIncrement is evil
 return -.5f*(postFix* sin( (t*d-s)*(2*PI)/p )) + b;
 } 
 float postFix =  a*pow(2,-10*(t-=1)); // postIncrement is evil
 return postFix * sin( (t*d-s)*(2*PI)/p )*.5f + c + b;
}
參數的意思:

  • t – 動畫中當前的時間
  • b – 開始值
  • c – 結束值
  • d – 動畫的總時間
看看 Java 的 第一行前三個的:

public class Sine {
	
	public static float  easeIn(float t,float b , float c, float d) {
		return -c * (float)Math.cos(t/d * (Math.PI/2)) + c + b;
	}
	
	public static float  easeOut(float t,float b , float c, float d) {
		return c * (float)Math.sin(t/d * (Math.PI/2)) + b;	
	}
	
	public static float  easeInOut(float t,float b , float c, float d) {
		return -c/2 * ((float)Math.cos(Math.PI*t/d) - 1) + b;
	}
	
}
雖然 Java 的也有了,但是話說這個怎麼用啊,跟上面的Interpolator如何聯繫起來啊?

一個簡單的方法:首先把 d 總時間設置爲固定值 1.0 ,把 b 開始值設置爲 0.0 把結束值設置爲1.0,然後把 t 當作上面 Interpolator 中的 float getInterpolation(float input);傳入值,此時不就能用上了?對不?

舉個Case

/**
 * Created by Qiujuer on 2015/1/5.
 */
public class InSineInterpolator implements Interpolator{
    public static float  easeIn(float t,float b , float c, float d) {
        return -c * (float)Math.cos(t/d * (Math.PI/2)) + c + b;
    }

    @Override
    public float getInterpolation(float input) {
        return easeIn(input, 0, 1, 1);
    }
}

使用

        //AnimatorSet
        mAnimatorSet = new AnimatorSet();
        mAnimatorSet.playTogether(aPaintX, aPaintY, aRadius, aBackground);
        mAnimatorSet.setInterpolator(new InSineInterpolator());
        mAnimatorSet.start();
可以看出使用與上面 Android 自帶的完全一樣,當然這個只是一個 Case ,具體使用中你可以隨意封裝,前提是別改動了主要部分。


好了,完成了,擦又是三個小時過去了,我的 LOL 又沒法打了。

最後送上福利,全部的實現類:



下載地址

Animation Interpolator.zip

願大家都能做出自己滿意的動畫!


——學之開源,用於開源;初學者的心態,與君共勉!

========================================================
作者:qiujuer
博客:blog.csdn.net/qiujuer
網站:www.qiujuer.net
開源庫:Genius-Android
轉載請註明出處:http://blog.csdn.net/qiujuer/article/details/42430269
========================================================

發佈了82 篇原創文章 · 獲贊 709 · 訪問量 66萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章