Android Animation學習(五) ApiDemos解析:容器布局動畫 LayoutTransition


 

Android Animation學習(五) ApiDemos解析:容器布局動畫 LayoutTransition

 

  Property animation系統還提供了對ViewGroup中的View改變加入動畫的功能。

  你可以使用 LayoutTransition 對ViewGroup中的View改變進行動畫顯示。

  注意,本文所說的動畫效果都是設置給容器(ViewGroup),然而效果是通過容器存放的View來體現的。

 

四種容器轉換動畫類型

  當你添加或者移除ViewGroup中的View時,或者你調用View的setVisibility()方法來控制其顯示或消失時,就處於一個轉換狀態。這種事件就有可能會激發動畫。

  當前被增加或者移除的View可以經歷一個出現的動畫或者一個消失的動畫。

  而且不止是當前要控制的View,ViewGroup中的其他View也可以隨之進行變動,比如經歷一個動畫移動到新的位置。

 

  所以一共有四種相關的動畫類型

  1.View本身的出現動畫;

  2.消失動畫;

  3.由於新增了其他View而需要改變位置的動畫;

  4.由於移除了其他View而需要改變位置的動畫。

  (如果增加或移除了其他View之后,當前View的位置不需要改變,則無動畫)。

 

  你可以自定義這些動畫,通過setAnimator() 方法把它們設置進一個 LayoutTransition 對象中去。

  設置的時候需要一個 Animator 對象和一個常數:

  APPEARING - A flag indicating the animation that runs on items that are appearing in the container.

  CHANGE_APPEARING - A flag indicating the animation that runs on items that are changing due to a new item appearing in the container.

  DISAPPEARING - A flag indicating the animation that runs on items that are disappearing from the container.

  CHANGE_DISAPPEARING - A flag indicating the animation that runs on items that are changing due to an item disappearing from the container.

 

  你可以自己定義這四種事件類型的動畫,也可以使用默認的動畫。

  最后通過setLayoutTransition(LayoutTransition)方法把這些動畫以一個 LayoutTransition 對象的形式設置給一個ViewGroup即可。

  比如下面這個方法就生成了一個全新的LayoutTransition對象並set給容器(ViewGroup類型),這樣四個動畫就全是默認動畫。

 

    // 重新生成LayoutTransition對象並設置給container
    private void resetTransition() {
        mTransitioner = new LayoutTransition();
        container.setLayoutTransition(mTransitioner);
    }

 

  為這個mTransitioner對象生成四個自定義動畫:

    // 生成自定義動畫
    private void setupCustomAnimations() {
        // 動畫:CHANGE_APPEARING
        // Changing while Adding
        PropertyValuesHolder pvhLeft = PropertyValuesHolder.ofInt("left", 0, 1);
        PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top", 0, 1);
        PropertyValuesHolder pvhRight = PropertyValuesHolder.ofInt("right", 0,
                1);
        PropertyValuesHolder pvhBottom = PropertyValuesHolder.ofInt("bottom",
                0, 1);
        PropertyValuesHolder pvhScaleX = PropertyValuesHolder.ofFloat("scaleX",
                1f, 0f, 1f);
        PropertyValuesHolder pvhScaleY = PropertyValuesHolder.ofFloat("scaleY",
                1f, 0f, 1f);

        final ObjectAnimator changeIn = ObjectAnimator.ofPropertyValuesHolder(
                this, pvhLeft, pvhTop, pvhRight, pvhBottom, pvhScaleX,
                pvhScaleY).setDuration(
                mTransitioner.getDuration(LayoutTransition.CHANGE_APPEARING));
        mTransitioner.setAnimator(LayoutTransition.CHANGE_APPEARING, changeIn);
        changeIn.addListener(new AnimatorListenerAdapter() {
            public void onAnimationEnd(Animator anim) {
                View view = (View) ((ObjectAnimator) anim).getTarget();
                view.setScaleX(1f);
                view.setScaleY(1f);
            }
        });

        // 動畫:CHANGE_DISAPPEARING
        // Changing while Removing
        Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
        Keyframe kf1 = Keyframe.ofFloat(.9999f, 360f);
        Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
        PropertyValuesHolder pvhRotation = PropertyValuesHolder.ofKeyframe(
                "rotation", kf0, kf1, kf2);
        final ObjectAnimator changeOut = ObjectAnimator
                .ofPropertyValuesHolder(this, pvhLeft, pvhTop, pvhRight,
                        pvhBottom, pvhRotation)
                .setDuration(
                        mTransitioner
                                .getDuration(LayoutTransition.CHANGE_DISAPPEARING));
        mTransitioner.setAnimator(LayoutTransition.CHANGE_DISAPPEARING,
                changeOut);
        changeOut.addListener(new AnimatorListenerAdapter() {
            public void onAnimationEnd(Animator anim) {
                View view = (View) ((ObjectAnimator) anim).getTarget();
                view.setRotation(0f);
            }
        });

        // 動畫:APPEARING
        // Adding
        ObjectAnimator animIn = ObjectAnimator.ofFloat(null, "rotationY", 90f,
                0f).setDuration(
                mTransitioner.getDuration(LayoutTransition.APPEARING));
        mTransitioner.setAnimator(LayoutTransition.APPEARING, animIn);
        animIn.addListener(new AnimatorListenerAdapter() {
            public void onAnimationEnd(Animator anim) {
                View view = (View) ((ObjectAnimator) anim).getTarget();
                view.setRotationY(0f);
            }
        });

        // 動畫:DISAPPEARING
        // Removing
        ObjectAnimator animOut = ObjectAnimator.ofFloat(null, "rotationX", 0f,
                90f).setDuration(
                mTransitioner.getDuration(LayoutTransition.DISAPPEARING));
        mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animOut);
        animOut.addListener(new AnimatorListenerAdapter() {
            public void onAnimationEnd(Animator anim) {
                View view = (View) ((ObjectAnimator) anim).getTarget();
                view.setRotationX(0f);
            }
        });

    }

 

 

默認的布局轉換動畫

  如果你要使用默認的動畫,一個非常簡單的方式是在ViewGroup的XML布局文件中把android:animateLayoutchanges 屬性設置為true。

  這樣就自動地按照默認方式來對要移除或添加的View,還有Group中的其他View進行動畫。

  比如ApiDemos中的LayoutAnimationsByDefault

<?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/addNewButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Add Button" />
    <!--
    <GridLayout
        android:columnCount="4"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/gridContainer"
        android:animateLayoutChanges="true"
        />
    -->

    <LinearLayout
        android:id="@+id/gridContainer"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:animateLayoutChanges="true" 
        android:orientation="vertical">
    </LinearLayout>

</LinearLayout>

  

  

  我把布局改成了線性布局,只要是ViewGroup類型都可以。

 

  默認情況下,DISAPPEARING和CHANGE_APPEARING動畫是立即開始的,其他動畫都有一個默認的開始延遲。

  這是因為,比如:當一個新的View出現的時候,其他View要立即執行CHANGE_APPEARING動畫騰出位置,而新出現的View在一定延遲之后再執行APPEARING出現;

  相反地,一個View消失的時候,它需要先DISAPPEARING動畫消失,而其他的View需要先等它消失后再執行CHANGE_DISAPPEARING。

  當然這些默認的行為都可以通過 setDuration(int, long) 和setStartDelay(int, long)等方法改變。

 

API Demos代碼

  ApiDemos中布局動畫相關的類有:LayoutAnimationsByDefault 、LayoutAnimations、LayoutAnimationsHideShow。

  完整的項目可以去github下載。https://github.com/mengdd/AnimationApiDemos

 

參考資料

  API Guides: Property Animation

  http://developer.android.com/guide/topics/graphics/prop-animation.html

  其中的Animating Layout Changes to ViewGroups

  LayoutTransition類Reference:

  http://developer.android.com/reference/android/animation/LayoutTransition.html

  項目地址:

  https://github.com/mengdd/AnimationApiDemos

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM