Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android屬性動畫簡析

Android屬性動畫簡析

編輯:關於Android編程

簡析

大家知道,我們在開發一款產品的時候為了達到良好的用戶體驗,我們可以在應用中適當的加上一些動畫效果,譬如平移、縮放、旋轉等等,但是這些常用的動畫在Android很早期的版本中就存在了,我們稱之為傳統動畫,傳統動畫一般分為Tween動畫和Frame動畫,這也是我們最常用的的動畫,統稱為Animation。傳統的Animation動畫實現上是通過不停的調用View的onDraw方法來重新繪制View來實現的。 在Android3.0以後,Google為Android新增了屬性動畫框架Animator,為什麼叫做屬性動畫呢?因為屬性動畫Animator不像傳統動畫那樣需要不停調用onDraw方法繪制界面,而且可以通過get、set方法,去真實的改變一個view的屬性的。Animation動畫僅僅給用戶一種“虛假”的動畫效果,其執行動畫view並沒有正在的改變自身的屬性,例如位置。而屬性動畫Animator,是真真正正的通過代碼將view“動畫”到了指定的位置了。

傳統動畫不能改變view真實屬性

下面,我們來看看傳統動畫實現的效果,我們使用很簡單的界面,給指定的ImageView設置上平移動畫,給ImageView指定點擊事件監聽,方便我們測試傳統動畫的局限性。
public class MainActivity extends Activity {

	private Button mButton;
	private ImageView mImageView;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		setContentView(R.layout.activity_main);
		mButton = (Button) findViewById(R.id.button);
		mImageView = (ImageView) findViewById(R.id.imageview);

		mButton.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				playAnim();
			}
		});
		mImageView.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				showToast();
			}
		});
	}

	/**
	 * 播放動畫
	 */
	protected void playAnim() {
		TranslateAnimation ta = new TranslateAnimation(0.0f, 200.0f, 0.0f, 0.0f);
		ta.setDuration(1000);
		ta.setFillAfter(true);
		mImageView.startAnimation(ta);
	}

	protected void showToast() {
		Toast.makeText(MainActivity.this, Hello, Toast.LENGTH_SHORT).show();
	}

}
\ 看到運行效果了吧,我們給ImageView的小機器人設置了點擊事件並且彈出Toast了,當我們點擊Button時,ImageView上的平移動畫被執行了,並且平移到了指定的位置(200px),然而我們在此時的ImageView上點擊時,並沒有彈出Toast提示,也就是說點擊的位置不在那裡,當我回頭再次點擊ImageView最初的位置時,Toast又被show了出來,這是不是很“詭異”?是的,上面的小例子足以說明,傳統的Animaion動畫只能改變動態視覺效果的動畫,並不能真實的去改變一個View的屬性(位置等)。而且,傳統的Animation動畫是通過不停的調用onDraw方法去繪制而完成的效果,這樣的實現方式很消耗資源(cpu)的。

API概述

描述 ValueAnimator 屬性動畫時序引擎也計算屬性動畫的值。它擁有所有的核心功能,計算動畫值,並包含每個動畫,有關時序的詳細信息是否動畫重復,聽眾接收更新事件,並設置自定義類型的能力評估。有兩件,以生動活潑的屬性:動畫值計算和設置這些對象的屬性動畫值。ValueAnimator不進行第二件,所以你一定要更新計算值ValueAnimator和修改你想用自己的邏輯動畫的對象。 ObjectAnimator ValueAnimator的子類,允許你設置一個目標對象和對象屬性的動畫。當計算出一個新的動畫值,本類更新相應的屬性。你大部分情況使用ObjectAnimator,因為它使得動畫的目標對象的值更簡單。然而,有時你直接使用ValueAnimator,因為ObjectAnimator有一些限制,如對目標對象目前要求的具體acessor方法。 AnimatorSet 提供機制,以組合動畫一起,讓他們關聯性運行。你可以設置動畫一起播放,順序,或在指定的延遲之後。 內容來自於:http://developer.android.com/guide/topics/graphics/prop-animation.html

ObjectAnimator

執行單個動畫

通常我們會使用ObjectAnimator類來為我們的view設置動畫,下面我們來簡單的看一下,使用了屬性動畫後,我們上述的小例子中的ImageView會發生哪些變化?修改上面的playAnim方法,將普通動畫換成屬性動畫:
protected void playAnim() {
		ObjectAnimator.ofFloat(mImageView, translationX, 0.0f, 200.0f).setDuration(1000).start();
}
\ 運行效果如上圖所示。對比上面的那幅圖看,發現當屬性動畫執行後,不但從視覺上改變了ImageView的位置,而且ImageView上的點擊事件的位置也跟著變化了,說明使用屬性動畫的View,實際上是真實的改變了一個View的屬性的。 從上面的一行代碼中,可以發現屬性動畫使用上是非常簡單的,ObjectAnimator中的ofFloat方法實際上是static方法,而且返回值還是一個ObjectAnimator對象。ofFloat的參數也很簡單,第1個參數是指定需要執行動畫的view,第2個參數是動畫模式,第三個參數是可變的數組,這裡需要描述動畫的初始位置和終點位置的坐標。 除了上面例子的中的translationX屬性,還可以指定translationY屬性,表示ImageView沿著Y軸的方向平移,然後我們也可以指定X或者Y,那麼translationX和X或者translationY和Y的區別,就是translationX是指定了ImageView在X軸上的偏移量,而單純的指定X表示ImageView被移動到指定的X軸上的位置,這點跟View的scrollTo和scrollBy方法有點類似。此外除了平移之外,還可以指定動畫的模式有: translationX、translationY rotation、rotationX、rotationY scaleX、scaleY X、Y alpha

ObjectAnimator繼承自ValueAnimator,要指定一個對象及該對象的一個屬性,當屬性值計算完成時自動設置為該對象的相應屬性,即完成了Property Animation的全部兩步操作。實際應用中一般都會用ObjectAnimator來改變某一對象的某一屬性,但用ObjectAnimator有一定的限制,要想使用ObjectAnimator,應該滿足以下條件:

對象應該有一個setter函數:set(駝峰命名法)如上面的例子中,像ofFloat之類的工場方法,第一個參數為對象名,第二個為屬性名,後面的參數為可變參數,如果values…參數只設置了一個值的話,那麼會假定為目的值,屬性值的變化范圍為當前值到目的值,為了獲得當前值,該對象要有相應屬性的getter方法:get如果有getter方法,其應返回值類型應與相應的setter方法的參數類型一致。

如果上述條件不滿足,則不能用ObjectAnimator,應用ValueAnimator代替。


多個動畫同時執行

PropertyValuesHolder

有時候我們需要同時執行多個屬性動畫的疊加效果的時候,可以使用PropertyValuesHolder工具類來“裝載”多種動畫,然後調用ObjectAnimator.ofPropertyValuesHolder()方法將裝載好的動畫交給ObjectAnimator去執行,例如:
protected void playAnim() {
		PropertyValuesHolder p1 = PropertyValuesHolder.ofFloat(translationX,0.0f, 200.0f);
		PropertyValuesHolder p2 = PropertyValuesHolder.ofFloat(translationY,0.0f, 200.0f);
		PropertyValuesHolder p3 = PropertyValuesHolder.ofFloat(rotation,0.0f, 360.0f);
		ObjectAnimator.ofPropertyValuesHolder(mImageView, p1, p2, p3).setDuration(2000).start();
}
\

AnimatorSet

跟普通的View動畫一樣,執行多種動畫效果時,屬性動畫也提供了動畫集方便我們執行多種動畫。
protected void playAnim() {
		Animator animator1 = ObjectAnimator.ofFloat(mImageView, translationX,0.0f, 200.0f);
		Animator animator2 = ObjectAnimator.ofFloat(mImageView, translationY,0.0f, 200.0f);
		Animator animator3 = ObjectAnimator.ofFloat(mImageView, rotation,0.0f, 360.0f);
		AnimatorSet set = new AnimatorSet();
		set.playTogether(animator1, animator2, animator3);
		set.setDuration(2000);
		set.start();
}

AnimationSet提供了一個把多個動畫組合成一個組合的機制,並可設置組中動畫的時序關系,如同時播放,順序播放等。

以下例子同時應用5個動畫:

播放anim1;同時播放anim2,anim3,anim4;播放anim5。
AnimatorSet bouncer = new AnimatorSet();
bouncer.play(anim1).before(anim2);
bouncer.play(anim2).with(anim3);
bouncer.play(anim2).with(anim4)
bouncer.play(anim5).after(amin2);
animatorSet.start();

動畫監聽事件

Android屬性動畫也為我們提供了對動畫播放過程的監聽器,我們只需要調用Animator.addListener()方法,將AnimatorListener對象傳遞進去就可以了:
anim.addListener(new Animator.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) {
		//動畫被取消時執行
	}
});
Animator.AnimatorListener對象下,有4個未實現的方法,我們可以分別實現一下其中的方法,就可以方便的去監聽動畫執行整個過程了。但是Animator.AnimatorListener對象不夠簡潔,因為大部分時候我們只需要監聽動畫結束時的事件即可,那麼Android也為我們提供好了一個簡化的監聽對象AnimatorListenerAdapter,AnimatorListenerAdapter
是個抽象類,其下面共有onAnimationCancel(),onAnimationEnd(),onAnimationPause(),onAnimationRepeat(),onAnimationResume(),onAnimationStart()幾個方法供我們調用,既然我們一般情況下僅僅是需要動畫結束時監聽,那麼我們就按照如下方式使用:
anim.addListener(new AnimatorListenerAdapter() {

	@Override
	public void onAnimationEnd(Animator animation) {
		// TODO Auto-generated method stub
		super.onAnimationEnd(animation);
	}

});

ValueAnimator

概念

ValueAnimator包含Property Animation動畫的所有核心功能,如動畫時間,開始、結束屬性值,相應時間屬性值計算方法等。應用Property Animation有兩個步聚:

計算屬性值根據屬性值執行相應的動作,如改變對象的某一屬性。

ValuAnimiator只完成了第一步工作,如果要完成第二步,需要實現ValueAnimator.onUpdateListener接口,這個接口只有一個函數onAnimationUpdate(),在這個函數中會傳入ValueAnimator對象做為參數,通過這個ValueAnimator對象的getAnimatedValue()函數可以得到當前的屬性值如:

 

protected void playAnim() {
		ValueAnimator animator = ValueAnimator.ofInt(0, 10);
		animator.setDuration(100);
		animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

			@Override
			public void onAnimationUpdate(ValueAnimator animation) {
				Log.i(TAG, AnimatedValue :  + animation.getAnimatedValue().toString());
			}
		});
		animator.start();
}
\

 

從上面的例子可以看到ValueAnimator類實現的是動畫的插值因子的計算,大部分情況下我們使用ObjectAnimator就可以輕松實現很多種動畫效果了,然後使用ObjectAnimator的View必須滿足有getter和setter方法,若沒有這些方法,使用ObjectAnimator的動畫是無法實現的,我們只好考慮使用ObjectAnimator的父類ValueAnimator了,ValueAnimator實現動畫不需要View含有getter和setter方法,它是通過計算動畫的插值因子,我們根據這個插值自定義動畫效果就可以了。

 

TypeEvaluator

TypeEvaluator是一個接口,通過實現該接口下的evaluate方法,可以實現我們自定義的各種復雜效果的動畫:

 

ValueAnimator animator =ValueAnimator.ofObject(new TypeEvaluator() {

	@Override
	public Number evaluate(float fraction, Number startValue,Number endValue) {
		// TODO Auto-generated method stub
		return null;
	}
});
上面就是實現的TypeEvaluator接口,下面有個未實現的方法,這個回調函數中提供如下三個參數:

 

fraction:插值因子,取值范圍0~1 startValue:動畫的起始值 endValue:動畫的結束值 我們可以根據這3個參數來編寫計算自己需要的動畫效果,樣式很多樣化的,不僅僅是ObjectAnimator裡幾種動畫類型了。由此可以看出,ValueAnimator比ObjectAnimator更加靈活,方式更加繁多,我們自定義動畫效果時,可以使用ValueAnimator實現TypeEvaluator接口來寫自己的動畫算法,實現比較復雜的動畫。

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved