Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android動畫譯文(上)

Android動畫譯文(上)

編輯:關於Android編程

1.概述

Android框架提供了兩套動畫系統

property animation 屬性動畫 view animation 視圖動畫

他們都有可取之處,不過總的來講。屬性動畫會更加靈活擁有更多特性。除此之外,你還可以使用(Drawable animation)圖片動畫,加載圖片資源然後一幀一幀的展示它們。

屬性動畫 Property Animation

屬性動畫可以操控一個對象的任何屬性,包括那些並沒有展示在屏幕上的屬性,Android3.0(API 11)引入。屬性動畫可擴展,你也可以操控自定義類型的屬性。

視圖動畫 View Animation

視圖動畫引入的更早,只能應用於視圖(View)上,他的使用簡單能滿足很多不同應用的需求。

圖片動畫 Drawable Animation

圖片動畫就像播放幻燈片一樣,一個接一個的展示圖片資源。如果你想展示的動畫可以很方便的用圖片資源做到,你可以采用這種方式。

2.屬性動畫

屬性動畫非常強大,你可以通多它控制任何事物動起來。你可以定義一個動畫隨著時間的變化來使一個對象的任何屬性改變,不管它是否在屏幕上顯示。概括地說,屬性動畫是在某一個特定的時間內改變一個對象的某個屬性值(對象的一個字段)。通過指定想要改變的屬性來達到使某個事物動起來的目的,比如,改變某個對象在屏幕上的位置,這個動畫持續的時間,它的位置從哪裡變到哪裡等等。

屬性動畫可以定義動畫的以下特性:

Duration:指定動畫時間。默認為300ms Time interpolation:屬性值對時間的變化函數 Repeat count and behavior:指定動畫在完成後是否重復,重復多少次。也可以指定讓這個動畫反向執行。 Animator sets:可以把一系列動畫放在一起同時執行或者在指定間隔之後有序執行。 Frame refresh delay:指定幀刷新間隔

屬性動畫工作原理 How Property Animation Works

首先,讓我們通過一個簡單的例子來了解動畫。圖1 是一個假想物體x屬性變化的動畫,也即其在屏幕上的水平位置的變化。動畫時間是40ms,移動距離為40像素。默認幀刷新頻率為10ms,每10ms,物體移動10像素。40ms時動畫結束,這個物體停在水平距離40px的位置。這是一個線性插值器的動畫的例子。也就是說物體勻速運動。
圖1.線性動畫
你也可以指定一些非線性插值器的動畫。圖2 闡述這樣一個例子,物體先加速,後減速運動。依然在40ms內移動40像素,但是是非線性運動。一開始,動畫加速到中點,其後減速直到動畫結束。就像圖2顯示的,物體在開始和結束時移動的距離要比中間移動的少。
圖2.非線性動畫

接下來我們再來仔細看看,上面這些動畫中,屬性動畫內的重要組件是如何運算的。圖3展示了主要的類之間如何工作的。<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPjxpbWcgYWx0PQ=="動畫是如何運算的" src="/uploadfile/Collfiles/20160720/20160720091211987.png" title="\" />
ValueAnimator對象可以追蹤動畫的執行時間和屬性值的變化。其內封裝了一個TimeInterpolator和一個TypeEvaluator,用來定義動畫的插值和屬性的計算值。例如,圖2的插值器為AccelerateDecelerateInterpolator,類型評估器為IntEvaluator。

通過創建ValueAnimator對象然後指定執行動畫的屬性,並設置開始和結束值以及執行時間,之後調用start()方法,動畫便開始執行。整個動畫中,ValueAnimator會根據動畫周期和已經執行的時間來計算一個0到1之間執行率(elapsed fraction),執行率代表動畫完成的百分比,0代表完成0%,1代表完成100%。圖1中當執行時間t=10ms時,因為總時間為40ms,所以執行率為0.25。

ValueAnimator計算完執行率後,就調用當前的TimeInterpolator來計算插值(interpolated fraction)。插值會依據當前的時間插值器有所不同。比如,圖2中動畫開始加速慢,插值約等於0.15,而圖1,插值和執行率始終相同,插值為0.25。

插值計算完成後,ValueAnimator調用合適的TypeEvaluator,然後依據插值,屬性的初始值和結束值來計算當前的屬性值。例如,圖2執行時間t=10ms時插值為0.15,所以對應的屬性值(位移)應該為 0.15 X (40 - 0), or 6.

屬性動畫和視圖動畫的區別 How Property Animation Differs from View Animation

視圖動畫只能適用於View對象,如果你想應用動畫在non-View對象,就必須自己實現代碼。 視圖動畫的應用有局限性,View對象只有很少一些方面的動畫,比如縮放比例、旋轉角度,但是不能改變背景顏色之類。 視圖動畫另一個弊端是,它只能改變視圖繪制的位置,而不是視圖實際在的位置。比如,如果你添加動畫去移動一個按鈕到另外的位置,按鈕正確繪制,但是按鈕的響應位置並不會改變。 使用屬性動畫,就沒有這些限制,你可以對任何對象(View and non-View)的任何屬性添加動畫,並且對象本身也的確被改變。屬性動畫的執行方式更加強大。你可以指定動畫執行者你想要改變的屬性,比如顏色、位置、尺寸並且你可以定義動畫的各個方面,比如插值器,多動畫的同步執行等。 不過視圖動畫設置容易,代碼編寫簡單。所以,如果視圖動畫能夠勝任你的需求,或者現有代碼工作正常,便沒有必要使用屬性動畫。值得一提的是,有時候也會出現即使用屬性動畫也使用視圖動畫的情況。

屬性動畫接口概覽 API Overview

你可以在android.animation包下找到所有屬性動畫的API。android.view.animation還包下定義了許多插值器可供使用。下面的表格,展示了屬性動畫的主要組件。

Animator類是創建動畫的基類。一般情況不會直接使用它,因為它只提供了一些基本的抽象方法。下面是它的一些子類。

Class Description ValueAnimator 屬性動畫的主要時間引擎,並計算執行動畫的屬性的值。它內部有計算動畫參數需要的所有的核心方法以及每個動畫的時間細節,還有一些其他信息如,動畫是否重復,接收動畫更新的監聽者,設置自定義類型。對屬性執行動畫包括兩方面:計算屬性變化後的值並將其設置給動畫執行對象。ValueAnimator並不執行第二方面,所以你必須監聽屬性值的更新,然後添加自己的邏輯對動畫執行對象進行相應的改變。 ObjectAnimator 是ValueAnimator的子類,你可以設置目標對象和目標屬性來添加動畫。該類在根據當前動畫計算出一個值後就更新相應的屬性值。多數情況,都是使用ObjectAnimator,因為它簡化了添加動畫的過程。不過有時候還是需要直接使用ValueAnimator,因為ObjectAnimator有一些局限,比如屬性必須有getter和setter方法。 AnimatorSet 提供一種多個動畫分組執行的機制。你可以設置動畫一起同時執行或者延時後執行。

Evaluators 告訴動畫如何計算指定屬性的值。它通過Animator類提供的時間數據以及動畫的屬性的開始結束值來計算。屬性動畫提供了一下幾種evaluators:

Class/Interface Description IntEvaluator int類型的默認evaluator FloatEvaluator float類型的默認evaluator ArgbEvaluator 十六進制顏色值的默認evaluator TypeEvaluator 通過該接口可以自定義Evaluator。如果你添加動畫的屬性值不是int/float/color,就必須自己實現TypeEvaluator來指定如何計算對象的屬性值。

時間插值器定義指定值隨時間變化的函數。例如,你可以指定動畫線性變化,也可以指定動畫非線性變化。下表展示了android.view.animation包下包含的插值器。如果系統提供的插值器不能滿足需求,可以實現TimeInterpolator自定義插值器。

Class/Interface Description AccelerateDecelerateInterpolator 變化率開始慢中間快 AccelerateInterpolator 變化率由慢變快 AnticipateInterpolator 先反向然後猛得向前 BounceInterpolator 彈到最終值 CycleInterpolator 重復指定圈數 DecelerateInterpolator 開始快然後慢慢減速 LinearInterpolator 勻速變化 OvershootInterpolator 猛的向前超越目標值後停在最終值 TimeInterpolator 自定義插值器的接口

使用ValueAnimator執行動畫 Animating with ValueAnimator

ValueAnimator類可以通過制定一系列int,float,color值來指定某類型的值在動畫時間內變化。可以通過以下工廠方法來獲得ViewAnimator的實例:ofInt(),ofFloat(),ofObject()。例如:

ValueAnimator animation = ValueAnimator.ofFloat(0f, 1f);
animation.setDuration(1000);
animation.start();

你也可以通過以下方式指定自定義類型添加動畫:

ValueAnimator animation = ValueAnimator.ofObject(new MyTypeEvaluator(), startPropertyValue, endPropertyValue);
animation.setDuration(1000);
animation.start();

上面的代碼片段並沒有實際效果,因為ValueAnimator 並沒有直接操作一個對象的屬性。你最想要做的應該還是通過這些計算值來改變你想要添加動畫的對象。可以通過在動畫生命周期中對 ValueAnimator 添加監聽然後處理這些監聽來達到目的。比如幀更新。實現監聽者時,可以通過getAnimatedValue() 來獲得每一幀更新時指定屬性的值。

使用ObjectAnimator執行動畫 Animating with ObjectAnimator

ObjectAnimator時ValueAnimator的子類,包含時間引擎和目標對象的屬性值計算。這讓對象的動畫的更容易添加,因為你不再需要實現Value.AnimatorUpdateListener 因為動畫屬性會自動更新。
實例化ObjectAnimator的方式和ValueAnimator類似,不過你需要指定變化的屬性名(字符串形式) 。

ObjectAnimator anim = ObjectAnimator.ofFloat(foo, "alpha", 0f, 1f);
anim.setDuration(1000);
anim.start();

想要ObjectAnimator正確的更新屬性值,你需要注意以下幾點:

動畫變化的屬性必須有set() 形式的setter方法,因為ObjectAnimator會在動畫期間自動更新屬性,因此如果屬性名為foo 它必須通過一個setFoo() 的方法來設置屬性。如果屬性沒有這個方法,你有以下三個選擇:

在對應類裡給屬性添加setter方法 用包裹類接收對應屬性值然後添加setter方法給原始對象設置屬性值。 使用ValueAnimator替代

如果你只指定了ObjectAnimator工廠方法中的一個參數,這個參數只能是指定屬性的結束值。因此,動畫屬性必須有get() 形式的getter方法來獲得屬性的初始值。

屬性的getter和setter方法對應的屬性類型必須和ObjectAnimator中指定的類型相同。比如,如果你的用以下方式構造ObjectAnimator,那麼目標對象一定要有targetObject.setPropName(float) 和targetObject.getPropName(float) 。

ObjectAnimator.ofFloat(targetObject, "propName", 1f)
依據動畫執行的屬性和對象的不同,你也許會調用invalidate() 方法來強制刷新界面,使視圖重繪來更新屬性。這些應該在onAnimationUpdate() 回調函數中執行。比如,執行動畫改變一個圖片的顏色屬性,會刷新屏幕使視圖重繪。View中其他類似的setter比如setAlpha() 和setTranslationX() 都會合理的刷新視圖,所以你不需要在屬性值改變時主動地去刷新界面。

使用AnimatorSet編排多個動畫 Choreographing Multiple Animations with AnimatorSet

很多情況下,你需要依據一個動畫的開始或者結束來播放另一個動畫。Android系統提供了AnimatorSet來將多個動畫綁定起來,這樣就可以指定是同時有序的開始還是一定間隔後播放這些動畫。AnimatorSet也可以互相嵌套。

下面這段代碼通過以下步驟播放下面的Animator對象:
1. 播放bounceAnim
2. 同時播放squashAnim1, squashAnim2, stretchAnim1, and stretchAnim2
3. 播放bounceBackAnim
4. 播放fadeAnim

AnimatorSet bouncer = new AnimatorSet();
bouncer.play(bounceAnim).before(squashAnim1);
bouncer.play(squashAnim1).with(squashAnim2);
bouncer.play(squashAnim1).with(stretchAnim1);
bouncer.play(squashAnim1).with(stretchAnim2);
bouncer.play(bounceBackAnim).after(stretchAnim2);
ValueAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
AnimatorSet animatorSet = new AnimatorSet();
animatorSet.play(bouncer).before(fadeAnim);
animatorSet.start();

動畫的監聽 Animation Listeners

你可以在動畫執行期間通過下面這些監聽者監聽一些重要的事件。

Animator.AnimatorListener

onAnimationStart() -動畫開始時調用 onAnimationEnd()- 動畫結束時調用 onAnimationRepeat() -動畫重復時調用 onAnimationCancel()-動畫取消時調用,同時也調用onAnimationEnd() ,不管動畫如何結束。

ValueAnimator.AnimatorUpdateListener
-onAnimationUpdate()-每一幀動畫都會調用。監聽這個事件來使用由ValueAnimator計算的屬性值。通過getAnimatedValue() 來獲取這個值。

如果你不想實現Animator.AnimatorListener 接口的所有方法,你也可以通過繼承AnimatorListenerAdapter類來代替。它提供了對Animator.AnimatorListener 接口的空的實現方法。你可以有選擇的去重寫。例如下面的例子,創建一個AnimatorListenerAdapter類並只重寫onAnimationEnd() 回調方法。

ValueAnimatorAnimator fadeAnim = ObjectAnimator.ofFloat(newBall, "alpha", 1f, 0f);
fadeAnim.setDuration(250);
fadeAnim.addListener(new AnimatorListenerAdapter() {
public void onAnimationEnd(Animator animation) {
    balls.remove(((ObjectAnimator)animation).getTarget());
}

ViewGroup布局改變的動畫 Animating Layout Changes to ViewGroups

屬性動畫能既能給ViewGroup對象添加動畫也能很方便的給View本身添加動畫。

當ViewGroup調用一個View的setVisibility()方法想要使ViewGroup內的View執行出現和消失的動畫時。可以通過LayoutTransiton類在ViewGroup內部執行動畫。當添加或者刪除View時,ViewGroup內剩余的View也能計算他們的新的位置。通過調用setAnimator()然後傳遞一個帶有以下常量之一的Animator對象可以在LayoutTransition對象內定義以下的動畫:

APPEARING -容器中的條目出現時執行動畫的標志 CHANGE_APPEARING -容器中新條目出現時其他條目執行動畫的標志 DISAPPEARING -容器中條目消失時執行動畫的標志 CHANGE_DISAPPEARING -容器中條目消失時其他條目執行動畫的標志

你可以使用默認動畫也可以為以上四種情況自定義動畫來個性化布局的過渡。

通過在布局文件中在對應布局下將android:animateLayoutchanges 屬性設置為true即可開啟ViewGroup的默認動畫,例如:

這樣ViewGroup內的條目在添加和移除時就會使用默認動畫。

使用TypeEvaluator

如果操作動畫改變的屬性類型是android系統沒有的,那麼我們可以通過實現TypeEvaluator接口來自定義評估器。int,float,color所對應的評估器分別為IntEvaluator,FloatEvaluator和ArgbEvaluator。

TypeEvaluator接口內只有一個需要實現的方法evaluate()。用來給動畫執行者在合適的時間返回一個合適的值。看看FloatEvaluator內部如何實現的:

public class FloatEvaluator implements TypeEvaluator {

    public Object evaluate(float fraction, Object startValue, Object endValue) {
        float startFloat = ((Number) startValue).floatValue();
        return startFloat + fraction * (((Number) endValue).floatValue() - startFloat);
    }
}

代碼中的fraction的值取決於當前選用的插值器的類型。插值器計算好插值便傳遞給當前的評估器。

使用插值器 Using Interpolators

插值器定義動畫中特定值隨時間變化的函數,比如前面的例子。插值器接收動畫的執行率(elapsed fraction)作為參數。不同的動畫效果對應不同的插值器。Android系統默認提供了一些插值器在android.view.animation 包下。如果它們都不能滿足需求,便只能自己實現TimeInterpolator來自定義插值器。

前面講過LinearInterpolator不受動畫執行率的影響,而AccelerateDecelerateInterpolator 先加速後減速。下面將兩者作對比,看看他們內部的實現邏輯:
AccelerateDecelerateInterpolator

public float getInterpolation(float input) {
    return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
}

LinearInterpolator

public float getInterpolation(float input) {
    return input;
}

下面的表格列出在一個動畫中1000ms內根據兩種插值器計算出的近似值:

運行時間(ms) 插值(線性插值器) 插值(加速減速插值器) 0 0 0 200 0.2 0.1 400 0.4 0.345 600 0.6 0.8 800 0.8 0.9 1000 1 1

可以看出線性插值器計算結果的變化率相同,每200ms變化0.2。而加速減速插值器的變化先慢後快。

指定關鍵幀 Specifying Keyframes

關鍵幀由“時間/值”這樣一對數據組成,指定動畫中特定時間的某個特定狀態。每個關鍵幀可以有單獨的插值器來控制動畫在前一幀和當前幀期間的行為。

實例化關鍵幀需要使用工廠類方法。使用ofInt()``ofFloat()``ofObject() 確定關鍵幀類型。之後調用ofKeyFrame() 工廠方法獲得一個PropertyValuesHolder 之後通過Animator的.ofPropertyValuesHolder(target,mPropertyValuesHolder) 方法就能獲得由關鍵幀定義的動畫,示例如下:

Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
Keyframe kf1 = Keyframe.ofFloat(.5f, 360f);
Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe("rotation", kf0, kf1, kf2);
ObjectAnimator rotationAnim = ObjectAnimator.ofPropertyValuesHolder(target, pvhRotation)
rotationAnim.setDuration(5000ms);

給視圖添加動畫 Animating Views

視圖動畫通過改變視圖繪制方式來改變視圖。不過這些改變是在一個“容器”中完成的,因為視圖本身沒有可操作的屬性。這就導致了視圖執行了動畫,但是其本身的屬性並沒有改變。所以,視圖其實依然存在於原始位置,雖然他看起來已經移動了。在Android3.0中,對View添加了新的屬性以及對應的getter和setter方法,來消除這個缺陷。

屬性動畫便是通過改變視圖的屬性來達到真實改變視圖的目的。並且,當屬性改變時,視圖會自動調用invalidate()方法來刷新屏幕。以下是為視圖新添加的屬性以便於應用屬性動畫。

translationX 和 translationY:通過控制xy軸坐標來控制視圖在容器中的位置移動。 rotation, rotationX, 和rotationY: 控制視圖繞著軸心的2D或者3D旋轉 scaleX and scaleY: 控制視圖的2D縮放 pivotX and pivotY: 控制軸心點。默認軸心點為視圖中心 x 和 y:xy軸坐標 alpha:視圖的透明度

對視圖添加動畫改變其某個屬性,比如:顏色,旋轉角度等,你只需要創建屬性動畫然後指定屬性就可以了。例如:

ObjectAnimator.ofFloat(myView, "rotation", 0f, 360f);

使用ViewPropertyAnimator添加動畫 Animating with ViewPropertyAnimator

ViewPropertyAnimator內置了一個Animator對象,提供了一種同時改變視圖多個屬性的簡單地方法。用法跟ObjectAnimator類似,也能實際的改變視圖的屬性。不過同時改變多個屬性時,它更高效,而且代碼可讀性更強。下面的代碼片段目的是同時改變視圖的x和y屬性,分別通過多個ObjectAnimator或一個ObjectAnimator或一個ViewPropertyAnimator來完成。

多個ObjectAnimator對象
ObjectAnimator animX = ObjectAnimator.ofFloat(myView, "x", 50f);
ObjectAnimator animY = ObjectAnimator.ofFloat(myView, "y", 100f);
AnimatorSet animSetXY = new AnimatorSet();
animSetXY.playTogether(animX, animY);
animSetXY.start();
一個ObjectAnimator 對象
PropertyValuesHolder pvhX = PropertyValuesHolder.ofFloat("x", 50f);
PropertyValuesHolder pvhY = PropertyValuesHolder.ofFloat("y", 100f);
ObjectAnimator.ofPropertyValuesHolder(myView, pvhX, pvyY).start();
一個ViewPropertyAnimator對象
targetView.animate().x(50f).y(100f);
    //注 :View 中的animate方法返回ViewPropertyAnimator 對象
    public ViewPropertyAnimator animate() {
        if (mAnimator == null) {
            mAnimator = new ViewPropertyAnimator(this);
        }
        return mAnimator;
    }

通過XML聲明動畫 Declaring Animations in XML

屬性動畫也可以通過XML文件來聲明。這樣可以更方便的在多個activity中復用動畫,編輯動畫順序也更容易。

不過為了區別傳統的視圖動畫文件,從API 3.1開始,應該把屬性動畫得XML文件放在res/animator目錄下。

屬性動畫類名對應的XML標簽如下:

ValueAnimator - AnimatorSet - ObjectAnimator -

下面這個例子同時播放兩套屬性動畫:


    
        
    

為了播放動畫,必須將XML文件設置給一個AnimatorSet對象,然後指定動畫的目標對象,然後開始動畫。例如:

AnimatorSet set = (AnimatorSet) AnimatorInflater.loadAnimator(myContext,
    R.anim.property_animator);
set.setTarget(myObject);
set.start();
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved