天天看點

Android動畫解析 View動畫,幀動畫與屬性動畫

Android的動畫形式共分為三種,View動畫,幀動畫與屬性動畫。

先對這三種動畫做一個概述:

View動畫是一種漸進式動畫,通過圖像的平移、縮放、旋轉和透明度等各種漸進式變換完成動畫效果。

幀動畫是通過不停的切換圖檔實作動畫效果。

屬性動畫是不停的改變對象的屬性來實作動畫效果。

View動畫:

Android系統提供的View動畫分為四類,RotateAnimation,ScaleAnimation,TranslateAnimation,AlphaAnimation,此外,Android還提供了AnimationSet,将四種動畫進行組合使用。View動畫可以通過setDuration方法,setInterpolator方法,setAnimationListener和setFillAfter方法來設定動畫運作的時長,動畫的播放速度,對動畫進行監聽和動畫運作結束後View的狀态。

View動畫還可以為ViewGroup和Activity設定動畫。

幀動畫:

幀動畫就是不停的切換圖檔來實作動畫效果,就如同小人書,但比較容易出現OOM,是以在使用時,需要注意圖檔大小。

屬性動畫:

View動畫的那四種效果有很明顯的缺點,繪制出來的效果其實并沒有真正改變View的屬性,即left、top、right和bottom的值,隻是系統臨時繪制的結果。這樣View的點選位置并沒有發生變化。針對這個問題,從Android3.0開始屬性動畫應運而生。

屬性動畫本質是通過改變新增的屬性(如平移translationX/Y、縮放scaleX/Y、旋轉rotationX/Y等)并重新整理螢幕來實作動畫效果,并且實作點選位置的實時改變。但是屬性動畫仍然不會修改原始的上下左右四個值。最後需要注意的是,屬性動畫不止用于View,還可以用于任何對象。

ValueAnimator是整個屬性動畫機制中最核心的一個類,屬性動畫的運作機制是通過不斷地對值進行操作來實作的,而初始值和結束值之間的動畫過渡就是由ValueAnimator類來負責計算的。它的内部使用一種時間循環的機制來計算值與值之間的動畫過渡,我們隻需要将初始值和結束值提供給ValueAnimator,并且告訴它動畫所需運作的時長,那麼ValueAnimator就會自動幫我們完成從初始值平滑地過渡到結束值這樣的效果。除此之外,ValueAnimator還負責管理動畫的播放次數、播放模式、以及對動畫設定監聽器等,确實是一個非常重要的類。

ObjectAnimator是我們最常接觸的類,它繼承自ValueAnimator。由于ValueAnimator隻是對值進行了一個平滑的動畫過渡,我們在實際中應用的場景并不多。而ObjectAnimator就不同了,它可以直接對任意對象的任意屬性進行動畫操作,例如 alpha, rotation, translationX, translationY, scaleX, scaleY等。我們同樣可以使用AnimationSet來将不同屬性的動畫進行組合。

Animator監聽器

Animator類中提供了addListener方法來對屬性動畫進行監聽,這個方法接收一個AnimationListener,我們隻需要實作AnimationListener就可以監聽動畫的各種事件了。我們已經知道了ObjectAnimator繼承自ValueAnimator,而ValueAnimator又繼承自Animator,是以,ObjectAnimator與ValueAnimator都可以使用addListener方法來對動畫進行監聽。

anim.addListener(new AnimatorListener() {  
        @Override  
        public void onAnimationStart(Animator animation) {  
        }  
      
        @Override  
        public void onAnimationRepeat(Animator animation) {  
        }  
      
        @Override  
        public void onAnimationEnd(Animator animation) {  
        }  
      
        @Override  
        public void onAnimationCancel(Animator animation) {  
        }  
    });  
           

但有時候我們并不會使用AnimationListener中的所有方法,這就會造成出現很多空方法的狀況。這種情況下,我們可以使用AnimationListenerAdapter,裡面已經定義了每個方法的空方法,我們隻需要重寫我們需要的方法就可以了。

Animator類還可添加更新監聽器,如下,

valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                Point point = (Point)animation.getAnimatedValue();
                circle.x = point.getX();
                circle.y = point.getY();
                circle.invalidate();
            }
        })
           

在AnimatorUpdateListener接口中的onAnimationUpdate方法中,調用animation.getAnimatedValue()方法即可獲得Animator更新後的最新屬性(ObjectAnimator)或值(ValueAnimator)。

插值器TimeInterpolator與估值器TypeEvaluator

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);
}
           
public interface TypeEvaluator<T> {

    /**
     * This function returns the result of linearly interpolating the start and end values, with
     * <code>fraction</code> representing the proportion between the start and end values. The
     * calculation is a simple parametric calculation: <code>result = x0 + t * (x1 - x0)</code>,
     * where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
     * and <code>t</code> is <code>fraction</code>.
     *
     * @param fraction   The fraction from the starting to the ending values
     * @param startValue The start value.
     * @param endValue   The end value.
     * @return A linear interpolation between the start and end values, given the
     *         <code>fraction</code> parameter.
     */
    public T evaluate(float fraction, T startValue, T endValue);

}
           

插值器TimeInterpolator是用來控制動畫的節奏快慢的,估值器TypeEvaluator是用來控制動畫的實作的。

TimeInterpolator接口中的getInterpolation方法接收一個float變量input,input的取值範圍為0~1,表示目前運作了的時間在設定時間中的位置,傳回值即為TypeEvaluator接口中evaluate方法中的參數fraction。evaluate方法根據傳入的fraction,起始值startValue,結束值endValue來控制動畫。ofFloat與ofInt預設使用FloatEvaluator類和IntEvaluator類。

public class FloatEvaluator implements TypeEvaluator<Number> {

    /**
     * This function returns the result of linearly interpolating the start and end values, with
     * <code>fraction</code> representing the proportion between the start and end values. The
     * calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>,
     * where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
     * and <code>t</code> is <code>fraction</code>.
     *
     * @param fraction   The fraction from the starting to the ending values
     * @param startValue The start value; should be of type <code>float</code> or
     *                   <code>Float</code>
     * @param endValue   The end value; should be of type <code>float</code> or <code>Float</code>
     * @return A linear interpolation between the start and end values, given the
     *         <code>fraction</code> parameter.
     */
    public Float evaluate(float fraction, Number startValue, Number endValue) {
        float startFloat = startValue.floatValue();
        return startFloat + fraction * (endValue.floatValue() - startFloat);
    }
}
           
public class IntEvaluator implements TypeEvaluator<Integer> {

    /**
     * This function returns the result of linearly interpolating the start and end values, with
     * <code>fraction</code> representing the proportion between the start and end values. The
     * calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>,
     * where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
     * and <code>t</code> is <code>fraction</code>.
     *
     * @param fraction   The fraction from the starting to the ending values
     * @param startValue The start value; should be of type <code>int</code> or
     *                   <code>Integer</code>
     * @param endValue   The end value; should be of type <code>int</code> or <code>Integer</code>
     * @return A linear interpolation between the start and end values, given the
     *         <code>fraction</code> parameter.
     */
    public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
        int startInt = startValue;
        return (int)(startInt + fraction * (endValue - startInt));
    }
}
           

從上面FloatEvaluator和IntEvaluator的evaluator方法,我們可以很清晰的看出,隻是将簡單的計算了startValue與endValue中間的fraction處的值傳回即可。

如果是ofObject方法,則需要自己定義TypeEvaluator,隻需實作TimeInterpolator接口即可。

如果不自定義TimeInterpolator,預設getInterpolation方法預設直接傳回input。我們可以使用setInterpolator方法設定自定義的TimeInterpolator。根據input計算不同的fraction,便可控制動畫運作的速率變化。

好了,屬性動畫就是這麼簡單,你學會了嗎?