1. 程式人生 > >使用LayoutTransition實現佈局變化時的動畫

使用LayoutTransition實現佈局變化時的動畫

在3.0及以後只需要在XML中設定animateLayoutChanges="true"或者在Java程式碼中新增一個LayoutTransition物件即可實現任何ViewGroup佈局改變時的動畫。

目前系統中支援以下5種狀態變化,應用程式可以為下面任意一種狀態設定自定義動畫:

1、APPEARING:容器中出現一個檢視。

2、DISAPPEARING:容器中消失一個檢視。

3、CHANGING:佈局改變導致某個檢視隨之改變,例如調整大小,但不包括新增或者移除檢視。

4、CHANGE_APPEARING:其他檢視的出現導致某個檢視改變。

5、CHANGE_DISAPPEARING:其他檢視的消失導致某個檢視改變。

下面舉個例項,動態的向容器中新增和移除元件來實現佈局變化得動畫效果,XML如下:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    
    <Button 
        android:id="@+id/main_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="新增控制元件"/>
    
    <LinearLayout 
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:animateLayoutChanges="true"
        android:id="@+id/main_container"
        android:orientation="vertical"/>

</LinearLayout>

注意在容器中設定了屬性android:animateLayoutChanges="true",這個時候容器佈局改變就已經有動畫效果了,只不過是系統預設的,比如新增一個按鈕會出現漸入動畫,移除一個按鈕會出現漸出動畫,而周圍的檢視則會平滑地填充移除時的空隙。

但是如果我們想自定義這些效果怎麼辦呢?使用LayoutTransition。程式碼如下:

public class MainActivity extends Activity implements OnClickListener {

	private LinearLayout mContainer;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		mContainer = (LinearLayout) findViewById(R.id.main_container);
		LayoutTransition transition = new LayoutTransition();
		mContainer.setLayoutTransition(transition);
		findViewById(R.id.main_btn).setOnClickListener(this);

		//使用翻轉進入的動畫代替預設動畫
		Animator appearAnim = ObjectAnimator
				.ofFloat(null, "rotationY", 90f, 0)
				.setDuration(transition.getDuration(LayoutTransition.APPEARING));
		transition.setAnimator(LayoutTransition.APPEARING, appearAnim);

		//使用翻轉消失的動畫代替預設動畫
		Animator disappearAnim = ObjectAnimator.ofFloat(null, "rotationX", 0,
				90f).setDuration(
				transition.getDuration(LayoutTransition.DISAPPEARING));
		transition.setAnimator(LayoutTransition.DISAPPEARING, disappearAnim);

		//使用滑動動畫代替預設佈局改變的動畫
		//這個動畫會讓檢視滑動進入並短暫地縮小一半,具有平滑和縮放的效果
		PropertyValuesHolder pvhSlide = PropertyValuesHolder.ofFloat("y", 0, 1);
		PropertyValuesHolder pvhScaleY = PropertyValuesHolder.ofFloat("scaleY",
				1f, 0.5f, 1f);
		PropertyValuesHolder pvhScaleX = PropertyValuesHolder.ofFloat("scaleX",
				1f, 0.5f, 1f);

		//這裡將上面三個動畫綜合
		Animator changingDisappearAnim = ObjectAnimator.ofPropertyValuesHolder(
				this, pvhSlide, pvhScaleY, pvhScaleX);
		changingDisappearAnim.setDuration(transition.getDuration(LayoutTransition.CHANGE_DISAPPEARING));
		transition.setAnimator(LayoutTransition.CHANGE_DISAPPEARING,
				changingDisappearAnim);
	}

	@Override
	public void onClick(View view) {
		Button btn = new Button(this);
		btn.setText("移除自己");
		btn.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				mContainer.removeView(v);
			}
		});
		mContainer.addView(btn, new LinearLayout.LayoutParams(
				LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
	}

mContainer.setLayoutTransition(transition)為容器繫結一個LayoutTransition物件。接下來為transition設定了幾種系統支援型別的佈局改變時動畫,動畫時間都是取系統預設的時間,另外關於屬性動畫ObjectAnimator的使用,可以參照guolin大神的部落格Android

最後一個過渡動畫稍微有點複雜,需要建立一個動畫,讓周圍的檢視可以平滑地運動到新的位置上,滑動的同時會產生縮放效果。為了實現這個效果,需要通過PropertyValuesHolder例項建立一個ObjectAnimator來設定一些屬性。動畫的每個屬性都是單獨的PropertyValuesHolder,並且通過ofPropertyValuesHolder工廠方法新增到Animator物件中。最後這個過渡動畫使移除的按鈕下面的所有按鈕向上滑動到剛剛空出的位置,同時稍微收縮一下。