Android屬性動畫PropertyAnimation系列三之LayoutTransition(佈局容器動畫)

  • 在上一篇中我們學習了屬性動畫的ObjectAnimator使用,不瞭解的可以看看 Android屬性動畫Property Animation系列一之ObjectAnimator。這一篇我們來學點新的東西。做項目的時候應該碰到這種問題:根據不同條件顯示或者隱藏一個控件或者佈局,我們能想到的第一個方法就是 調用View.setVisibility()方法。雖然實現了顯示隱藏效果,但是總感覺這樣的顯示隱藏過程很僵硬,讓人不是很舒服,那麼有沒有辦法能讓這種顯示隱藏有個過渡的動畫效果呢?答案是肯定的,不言而喻就是LayoutTransition類了。 
    上效果圖 
    這裏寫圖片描述

    實現上面的效果只需要在佈局容器中添加android:animateLayoutChanges=”true”屬性就ok了。不信你看 
    佈局文件如下:

    01.<code class=" hljs xml"><?xml version="1.0" encoding="utf-8"?>
    02.<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    03.android:layout_width="match_parent"
    04.android:layout_height="match_parent"
    05.android:orientation="vertical">
    06. 
    07.<LinearLayout
    08.android:layout_width="match_parent"
    09.android:layout_height="wrap_content"
    10.android:orientation="horizontal">
    11. 
    12.<Button
    13.android:layout_width="wrap_content"
    14.android:layout_height="wrap_content"
    15.android:onClick="buttonClick"
    16.android:text="添加控件" />
    17. 
    18.<Button
    19.android:layout_width="wrap_content"
    20.android:layout_height="wrap_content"
    21.android:onClick="buttonClick1"
    22.android:text="移除控件" />
    23.</LinearLayout>
    24. 
    25. 
    26.<LinearLayout
    27.android:id="@+id/parent"
    28.android:layout_width="match_parent"
    29.android:layout_height="wrap_content"
    30.android:animateLayoutChanges="true"
    31.android:orientation="vertical"></LinearLayout>
    32. 
    33.</LinearLayout></code>

    如果佈局容器中爲添加android:animateLayoutChanges=”true”默認是麼有動畫效果的。該屬性只能用在ViewGroup控件裏,表示容器裏面佈局改變時有默認的動畫效果,比如說添加控件,刪除控件的時候就是默認的動畫效果。

    以上動畫調用代碼如下:

    01.<code class=" hljs java">package com.xjp.animations;
    02. 
    03.import android.app.Activity;
    04.import android.os.Bundle;
    05.import android.view.View;
    06.import android.view.ViewGroup;
    07.import android.widget.Button;
    08.import android.widget.LinearLayout;
    09. 
    10./**
    11.* Description:
    12.* User: xjp
    13.* Date: 2015/5/22
    14.* Time: 15:06
    15.*/
    16. 
    17.public class LayoutAnimationActivity extends Activity {
    18. 
    19.private LinearLayout parent;
    20.private int i = 0;
    21.private int j = 0;
    22. 
    23.@Override
    24.protected void onCreate(Bundle savedInstanceState) {
    25.super.onCreate(savedInstanceState);
    26. 
    27.setContentView(R.layout.activity_layout_animation);
    28. 
    29.parent = (LinearLayout) findViewById(R.id.parent);
    30.}
    31. 
    32.public void buttonClick(View view) {
    33.addButtonView();
    34.}
    35. 
    36.public void buttonClick1(View view) {
    37.removeButtonView();
    38.}
    39. 
    40.private void addButtonView() {
    41.i++;
    42.Button button = new Button(this);
    43.button.setText("button" + i);
    44.LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
    45.ViewGroup.LayoutParams.WRAP_CONTENT);
    46.parent.addView(button, params);
    47.}
    48. 
    49.private void removeButtonView() {
    50.if (i > 0)
    51.parent.removeViewAt(0);
    52.}
    53.}
    54.</code>

    是不是發現很簡單?除了佈局中添加了android:animateLayoutChanges=”true”屬性,代碼中根本不需要做任何處理就有很舒服的過渡動畫效果了。主要是添加了該屬性之後在容器中有佈局改變時系統會默認給該容器添加一個默認的動畫效果。如果你覺得上面的的效果已經很nice~了,那你就太容易滿足了,我們除了使用系統默認的佈局容器動畫,還可以自定義佈局容器動畫。現在該LayoutTransition類上場了。

    LayoutTransition

    該類用於當前佈局容器中有View添加,刪除,隱藏,顯示的時候定義佈局容器自身的動畫和View的動畫。也就是說當一個LinerLayout中隱藏一個view的時候,我們可以自定義 整個LinerLayout容器因爲隱藏了view而改變的動畫,同時還可以自定義被隱藏的view自己消失時候的動畫。你可以先new一個LayoutTransition對象,通過setLayoutTransition()方法將對象設置進一個佈局容器ViewGroup中去。代碼如下:

    01.<code class=" hljs java">    private LinearLayout container;
    02.private LayoutTransition mTransitioner;
    03./**
    04.* 初始化容器動畫
    05.*/
    06.private void initTransition() {
    07.mTransitioner = new LayoutTransition();
    08.container.setLayoutTransition(mTransitioner);
    09.}</code>

    LayoutTransition類定義瞭如下幾種佈局容器動畫類型。

    APPEARING :當view出現或者添加的時候,view出現的動畫 DISAPPEARING :當view消失或者隱藏的時候,view消失的動畫 CHANGE_APPEARING :當添加view導致佈局容器改變的時候,整個佈局容器的動畫 CHANGE_DISAPPEARING :當刪除或者隱藏view導致佈局容器改變的時候,整個佈局容器的動畫

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

    LayoutTransition的用法

    APPEARING–view出現的動畫

    1.<code class=" hljs java">/**
    2.* view出現時 view自身的動畫效果
    3.*/
    4.ObjectAnimator animator1 = ObjectAnimator.ofFloat(null"rotationY", 0F, 90F, 0F);
    5.mTransitioner.setAnimator(LayoutTransition.APPEARING, animator1);</code>

    定義一個旋轉的屬性動畫,這裏將動畫對象置空,因爲系統內部會將添加的view設置爲動畫對象。然後調用setAnimator()方法將動畫設置進LayoutTransition對象mTransitioner中。

    完整動畫代碼如下,具體解釋都有註解

    001.<code class=" hljs java">package com.xjp.animations;
    002. 
    003.import android.animation.Animator;
    004.import android.animation.AnimatorListenerAdapter;
    005.import android.animation.Keyframe;
    006.import android.animation.LayoutTransition;
    007.import android.animation.ObjectAnimator;
    008.import android.animation.PropertyValuesHolder;
    009.import android.app.Activity;
    010.import android.os.Bundle;
    011.import android.view.View;
    012.import android.view.ViewGroup;
    013.import android.widget.Button;
    014.import android.widget.LinearLayout;
    015. 
    016./**
    017.* Description:佈局動畫Demo
    018.* User: xjp
    019.* Date: 2015/5/22
    020.* Time: 15:06
    021.*/
    022. 
    023.public class LayoutAnimationActivity extends Activity {
    024. 
    025. 
    026.private int i = 0;
    027.private LinearLayout container;
    028.private LayoutTransition mTransitioner;
    029. 
    030.@Override
    031.protected void onCreate(Bundle savedInstanceState) {
    032.super.onCreate(savedInstanceState);
    033. 
    034.setContentView(R.layout.activity_layout_animation);
    035. 
    036.container = (LinearLayout) findViewById(R.id.parent);
    037. 
    038.initTransition();
    039.setTransition();
    040.}
    041. 
    042./**
    043.* 初始化容器動畫
    044.*/
    045.private void initTransition() {
    046.mTransitioner = new LayoutTransition();
    047.container.setLayoutTransition(mTransitioner);
    048.}
    049. 
    050. 
    051.private void setTransition() {
    052./**
    053.* view出現時 view自身的動畫效果
    054.*/
    055.ObjectAnimator animator1 = ObjectAnimator.ofFloat(null"rotationY", 90F, 0F).
    056.setDuration(mTransitioner.getDuration(LayoutTransition.APPEARING));
    057.mTransitioner.setAnimator(LayoutTransition.APPEARING, animator1);
    058. 
    059./**
    060.* view 消失時,view自身的動畫效果
    061.*/
    062.ObjectAnimator animator2 = ObjectAnimator.ofFloat(null"rotationX", 0F, 90F, 0F).
    063.setDuration(mTransitioner.getDuration(LayoutTransition.DISAPPEARING));
    064.mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, animator2);
    065. 
    066./**
    067.* view 動畫改變時,佈局中的每個子view動畫的時間間隔
    068.*/
    069.mTransitioner.setStagger(LayoutTransition.CHANGE_APPEARING, 30);
    070.mTransitioner.setStagger(LayoutTransition.CHANGE_DISAPPEARING, 30);
    071. 
    072. 
    073./**
    074.* 爲什麼這裏要這麼寫?具體我也不清楚,ViewGroup源碼裏面是這麼寫的,我只是模仿而已
    075.* 不這麼寫貌似就沒有動畫效果了,所以你懂的!
    076.*/
    077.PropertyValuesHolder pvhLeft =
    078.PropertyValuesHolder.ofInt("left"01);
    079.PropertyValuesHolder pvhTop =
    080.PropertyValuesHolder.ofInt("top"01);
    081.PropertyValuesHolder pvhRight =
    082.PropertyValuesHolder.ofInt("right"01);
    083.PropertyValuesHolder pvhBottom =
    084.PropertyValuesHolder.ofInt("bottom"01);
    085. 
    086. 
    087./**
    088.* view出現時,導致整個佈局改變的動畫
    089.*/
    090.PropertyValuesHolder animator3 = PropertyValuesHolder.ofFloat("scaleX", 1F, 2F, 1F);
    091.final ObjectAnimator changeIn = ObjectAnimator.ofPropertyValuesHolder(
    092.this, pvhLeft, pvhTop, pvhRight, pvhBottom, animator3).
    093.setDuration(mTransitioner.getDuration(LayoutTransition.CHANGE_APPEARING));
    094.changeIn.addListener(new AnimatorListenerAdapter() {
    095.@Override
    096.public void onAnimationEnd(Animator animation) {
    097.View view = (View) ((ObjectAnimator) animation).getTarget();
    098.view.setScaleX(1.0f);
    099.}
    100.});
    101.mTransitioner.setAnimator(LayoutTransition.CHANGE_APPEARING, changeIn);
    102. 
    103. 
    104./**
    105.* view消失,導致整個佈局改變時的動畫
    106.*/
    107.Keyframe kf0 = Keyframe.ofFloat(0f, 0f);
    108.Keyframe kf1 = Keyframe.ofFloat(.5f, 2f);
    109.Keyframe kf2 = Keyframe.ofFloat(1f, 0f);
    110.PropertyValuesHolder pvhRotation =
    111.PropertyValuesHolder.ofKeyframe("scaleX", kf0, kf1, kf2);
    112.final ObjectAnimator changeOut = ObjectAnimator.ofPropertyValuesHolder(
    113.this, pvhLeft, pvhTop, pvhRight, pvhBottom, pvhRotation).
    114.setDuration(mTransitioner.getDuration(LayoutTransition.CHANGE_DISAPPEARING));
    115.changeOut.addListener(new AnimatorListenerAdapter() {
    116.@Override
    117.public void onAnimationEnd(Animator animation) {
    118.View view = (View) ((ObjectAnimator) animation).getTarget();
    119.view.setScaleX(1.0f);
    120.}
    121.});
    122.mTransitioner.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, changeOut);
    123.}
    124. 
    125. 
    126.public void buttonClick(View view) {
    127.addButtonView();
    128.}
    129. 
    130.public void buttonClick1(View view) {
    131.removeButtonView();
    132.}
    133. 
    134.private void addButtonView() {
    135.i++;
    136.Button button = new Button(this);
    137.button.setText("button" + i);
    138.LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
    139.ViewGroup.LayoutParams.WRAP_CONTENT);
    140.container.addView(button, Math.min(1, container.getChildCount()), params);
    141.}
    142. 
    143.private void removeButtonView() {
    144.if (i > 0)
    145.container.removeViewAt(0);
    146.}
    147.}
    148.</code>

    佈局文件

    01.<code class=" hljs xml"><?xml version="1.0" encoding="utf-8"?>
    02.<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    03.android:layout_width="match_parent"
    04.android:layout_height="match_parent"
    05.android:orientation="vertical">
    06. 
    07.<LinearLayout
    08.android:layout_width="match_parent"
    09.android:layout_height="wrap_content"
    10.android:orientation="horizontal">
    11. 
    12.<Button
    13.android:layout_width="wrap_content"
    14.android:layout_height="wrap_content"
    15.android:onClick="buttonClick"
    16.android:text="添加控件" />
    17. 
    18.<Button
    19.android:layout_width="wrap_content"
    20.android:layout_height="wrap_content"
    21.android:onClick="buttonClick1"
    22.android:text="移除控件" />
    23.</LinearLayout>
    24. 
    25. 
    26.<LinearLayout
    27.android:id="@+id/parent"
    28.android:layout_width="match_parent"
    29.android:layout_height="wrap_content"
    30.android:animateLayoutChanges="true"
    31.android:orientation="vertical"></LinearLayout>
    32. 
    33.</LinearLayout></code>

    最後來一張效果圖: 
    這裏寫圖片描述

    佈局動畫之layoutAnimation

    很多時候我們想要在第一次加載ListView或者GridView的時候能有個動畫效果來達到一個很好的過度效果。比如下面的效果 
    這裏寫圖片描述 
    實現這種效果只需要在佈局中添加android:layoutAnimation=”@anim/layout”屬性就好了。接下來我們來看看layout.xml動畫怎麼實現的?在res/anim目錄下新建layout.xml文件,代碼如下:

    1.<code class=" hljs xml"><?xml version="1.0" encoding="utf-8"?>
    2.<layoutAnimation xmlns:android="http://schemas.android.com/apk/res/android"
    3.android:animation="@anim/left"
    4.android:animationOrder="normal"
    5.android:delay="30%"></layoutAnimation></code>

    android:delay 子類動畫時間間隔 (延遲) 70% 也可以是一個浮點數 如“1.2”等 
    android:animationOrder=”random” 子類的顯示方式 random表示隨機 
    android:animationOrder 的取值有 
    normal 0 默認 
    reverse 1 倒序 
    random 2 隨機 
    android:animation=”@anim/left” 表示孩子顯示時的具體動畫是什麼代 
    在res/anim目錄下新建left.xml文件,碼如下:

    01.<code class=" hljs xml"><?xml version="1.0" encoding="utf-8"?>
    03.<translate
    04.android:duration="500"
    05.android:fromXDelta="100%"
    06.android:fromYDelta="0"
    07.android:toXDelta="0"
    08.android:toYDelta="0" />
    09.<alpha
    10.android:duration="500"
    11.android:fromAlpha="0"
    12.android:toAlpha="1" />
    13.</set></code>

    這樣就實現瞭如上ListView的動畫效果了。

    當然我們也可以在代碼中實現這種動畫效果

    01.<code class=" hljs cs">private void initAinm() {
    02.//通過加載XML動畫設置文件來創建一個Animation對象;
    03.Animation animation = AnimationUtils.loadAnimation(this, R.anim.left);
    04.//得到一個LayoutAnimationController對象;
    05.LayoutAnimationController lac = new LayoutAnimationController(animation);
    06.//設置控件顯示的順序;
    07.lac.setOrder(LayoutAnimationController.ORDER_REVERSE);
    08.//設置控件顯示間隔時間;
    09.lac.setDelay(1);
    10.//爲ListView設置LayoutAnimationController屬性;
    11.listView.setLayoutAnimation(lac);
    12.}</code>

    通過AnimationUtils.loadAnimation加載item的動畫來獲得一個Animation對象,然後將Animation對象設置到LayoutAnimationController中來獲得LayoutAnimationController對象,配置LayoutAnimationController對象的一些屬性。最後將LayoutAnimationController對象設置到ListView中。

    注意

    layoutAnimation動畫不僅僅限於ListView,GridView中,也可用於一切ViewGroup中。具體怎麼用就看項目需求了。

    總結

    Android屬性動畫至此就基本介紹完畢了。其中基本的動畫使用和實例也貼出來了,基本能滿足日常開發需求,當然有更炫的動畫時可以根據這些基礎去實現。這麼說,以後都可以不用補間動畫了?貌似屬性動畫更加合理,因爲這種動畫改變的是屬性而不僅僅是位置。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章