Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android布局動畫之animateLayoutChanges與LayoutTransition

Android布局動畫之animateLayoutChanges與LayoutTransition

編輯:關於Android編程

關於布局動畫是針對ViewGroup而言的,意指ViewGroup在增加子View或者刪除子View時其子View的過渡動畫,在android官網有這麼一個簡單的例子,其效果如下,接下來我們就通過這個例子來入門

\

最簡單的布局動畫實現

??事實上,實現上面ViewGroup的布局動畫非常簡單,我們只要給子View所在的ViewGroup的xml中添加下面的屬性即可:

android:animateLayoutChanges="true"

??通過設置以上代碼,當ViewGroup在添加View時,子View會呈現出過渡的動畫效果,這個動畫效果是android默認的顯示效果,而且無法使用自定義的動畫來替換這個效果,不過還是有其他方式可以實現自定義的過渡動畫滴,這個我們後面會分析,下面看看android官方給的demo的代碼實現:
activity_layout_changes.xml布局文件

<framelayout android:layout_height="match_parent" android:layout_width="match_parent" xmlns:android="http://schemas.android.com/apk/res/android">

    
    

        
        

    

    
    

</framelayout>

??布局代碼比較簡單,使用了一個ScrollView包裹了LinearLayout布局並在LinearLayout中添加了屬性android:animateLayoutChanges="true",啟動了android自帶的布局動畫,之所以使用ScrollView,是為了在添加子View多時可以進行滑動,而TextView只不過在沒有子view時一個提示語。接著看看子View的布局文件list_item_example.xml




    
    

    
    

??主要控件有用於顯示每個子View內容的TextView和用於響應刪除子View事件的ImageButton,最後就是Activity的實現:
LayoutChangesActivity.java

package com.example.android.animationsdemo;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.NavUtils;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

/**
 * This sample demonstrates how to use system-provided, automatic layout transitions. Layout
 * transitions are animations that occur when views are added to, removed from, or changed within
 * a {@link ViewGroup}.
 *
 * 

In this sample, the user can add rows to and remove rows from a vertical * {@link android.widget.LinearLayout}.

*/ public class LayoutChangesActivity extends Activity { private ViewGroup mContainerView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_layout_changes); mContainerView = (ViewGroup) findViewById(R.id.container); } @Override public boolean onCreateOptionsMenu(Menu menu) { super.onCreateOptionsMenu(menu); //響應添加事件的menu getMenuInflater().inflate(R.menu.activity_layout_changes, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: NavUtils.navigateUpTo(this, new Intent(this, MainActivity.class)); return true; case R.id.action_add_item: //添加子View findViewById(android.R.id.empty).setVisibility(View.GONE); addItem(); return true; } return super.onOptionsItemSelected(item); } private void addItem() { //實例化一個子View final ViewGroup newView = (ViewGroup) LayoutInflater.from(this).inflate( R.layout.list_item_example, mContainerView, false); // 隨機設置子View的內容 ((TextView) newView.findViewById(android.R.id.text1)).setText( COUNTRIES[(int) (Math.random() * COUNTRIES.length)]); //設置刪除按鈕的監聽 newView.findViewById(R.id.delete_button).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mContainerView.removeView(newView); // If there are no rows remaining, show the empty view. if (mContainerView.getChildCount() == 0) { findViewById(android.R.id.empty).setVisibility(View.VISIBLE); } } }); //添加子View mContainerView.addView(newView, 0); } /** * A static list of country names. */ private static final String[] COUNTRIES = new String[]{ "Belgium", "France", "Italy", "Germany", "Spain", "Austria", "Russia", "Poland", "Croatia", "Greece", "Ukraine", }; }

??代碼比較簡單,mContainerView作為子View的承載容器,我們可以不斷添加子View,也可以移除子View,由於我們在布局文件中啟動了android自帶的布局動畫,所以在添加子View或移除子View都會有過度動畫,現在運行程序,效果如下:
\
這就是android中最簡單的布局動畫

布局動畫實之layoutAnimation

??除了上面的布局動畫外,有時我們可能需要第一次加載ListView或者GridView的時候能有個動畫的過度效果,以便達到更好的體驗,如下ListView加載子View的效果:
\
??事實上實現這種效果也比較簡單,我們只需要在ListView的布局文件中添加android:layoutAnimation=”@anim/layout”屬性即可。接下來給出實現步驟:
實現動畫效果
left_into.xml



    
    

這個比較簡單,就一個平移和透明度的效果,接著創建layout_animation.xml

這裡簡單介紹一下layoutAnimation標簽屬性:

屬性名 含義 android:delay delay的單位為秒,表示子View進入的延長時間 android:animationOrder 子類的進入方式 ,其取值有,normal 0 默認 ,reverse 1 倒序 ,random 2 隨機 android:animation 子view要執行的具體動畫的文件,自定義即可

然後設置給listView控件即可,activity_listview.xml:




    
        android:layoutAnimation="@anim/layout_animation"
        >
    

ListViewActivity.java代碼如下:

package com.example.android.animationsdemo;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by zejian
 * Time 16/9/17.
 * Description:
 */
public class ListViewActivity extends Activity {

    private ListView listView;
    private List list;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_listview);
        listView= (ListView) findViewById(R.id.listView);
        initData();
        listView.setAdapter(new Myadpter());
    }

    public void initData(){
        list = new ArrayList<>();
        for(int i=1;i<30;i++){
            list.add("布局動畫listView測試_"+i);
        }
    }

    private  class  Myadpter extends BaseAdapter{

        @Override
        public int getCount() {
            return list.size();
        }

        @Override
        public Object getItem(int position) {
            return list.get(position);
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {

            TextView tv= new TextView(ListViewActivity.this);
            tv.setTextSize(20);
            tv.setHeight(100);
            tv.setText(list.get(position));
            return tv;
        }
    }
}

??執行以上代碼,效果就是前面我們給出listView進入的動態效果,這裡特別注意的是,動畫只在listView子View第一次進入時有效,如果後面動態給listView添加子View時,此動畫效果無效,當然除了通過xml設置外,我們還可以通過代碼動態設置,代碼范例如下,這裡就不演示了。

//通過加載XML動畫設置文件來創建一個Animation對象,子View進入的動畫
Animation animation=AnimationUtils.loadAnimation(this, R.anim.left_into);
//得到一個LayoutAnimationController對象;
LayoutAnimationController lac=new LayoutAnimationController(animation);
//設置控件顯示的順序;
lac.setOrder(LayoutAnimationController.ORDER_REVERSE);
//設置控件顯示間隔時間;
lac.setDelay(0.5f);
//為ListView設置LayoutAnimationController屬性;
listView.setLayoutAnimation(lac);

??通過AnimationUtils.loadAnimation加載子View的動畫來並返回一個Animation對象,然後將Animation對象設置到LayoutAnimationController中並返回LayoutAnimationController對象,配置LayoutAnimationController對象的一些屬性,最後設置到ListView中,其中LayoutAnimationController對應layoutAnimation標簽,這裡需要注意的是layoutAnimation動畫不僅僅限於ListView,GridView中,也可用於一切ViewGroup中。

布局動畫實之LayoutTransition

??前面我們說過ViewGroup在設置android:animateLayoutChanges="true"後在添加或者刪除子view時可以啟用系統帶著的動畫效果,但這種效果無法通過自定義動畫去替換。不過還好android官方為我們提供了LayoutTransition類,通過LayoutTransition就可以很容易為ViewGroup在添加或者刪除子view設置自定義動畫的過渡效果了。
??LayoutTransition類用於當前布局容器中需要View添加,刪除,隱藏,顯示時設置布局容器子View的過渡動畫。也就是說利用LayoutTransition,可以分別為需添加或刪除的View對象在移動到新的位置的過程添加過渡的動畫效果。我們可以通過setLayoutTransition()方法為布局容器ViewGroup設置LayoutTransition對象,代碼如下:

//初始化容器動畫
LayoutTransition mTransitioner = new LayoutTransition();
container.setLayoutTransition(mTransitioner);

一般地,Layout中的子View對象有四種動畫變化的形式,如下:

屬性值 含義 LayoutTransition.APPEARING 子View添加到容器中時的過渡動畫效果。 LayoutTransition.CHANGE_APPEARING 子View添加到容器中時,其他子View位置改變的過渡動畫 LayoutTransition.DISAPPEARING 子View從容器中移除時的過渡動畫效果。 LayoutTransition.CHANGE_DISAPPEARING 子View從容器中移除時,其它子view位置改變的過渡動畫 LayoutTransition.CHANGING 子View在容器中位置改變時的過渡動畫,不涉及刪除或者添加操作

下面給出一個例子,先看布局文件activity_layout_animation.xml



    

比較簡單不啰嗦,接著看看LayoutAnimationActivity.java


 package com.example.android.animationsdemo;

import android.animation.LayoutTransition;
import android.animation.ObjectAnimator;
import android.animation.PropertyValuesHolder;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.LinearLayout;

/**
 * Created by zejian
 * Time 16/9/17.
 * Description:
 */
public class LayoutAnimationActivity extends Activity {


    private int i = 0;
    private LinearLayout container;
    private LayoutTransition mTransitioner;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_layout_animation);

        container = (LinearLayout) findViewById(R.id.container);
        //構建LayoutTransition
        mTransitioner = new LayoutTransition();
        //設置給ViewGroup容器
        container.setLayoutTransition(mTransitioner);
        setTransition();
    }


    private void setTransition() {
        /**
         * 添加View時過渡動畫效果
         */
        ObjectAnimator addAnimator = ObjectAnimator.ofFloat(null, "rotationY", 0, 90,0).
                setDuration(mTransitioner.getDuration(LayoutTransition.APPEARING));
        mTransitioner.setAnimator(LayoutTransition.APPEARING, addAnimator);

        /**
         * 移除View時過渡動畫效果
         */
        ObjectAnimator removeAnimator = ObjectAnimator.ofFloat(null, "rotationX", 0, -90, 0).
                setDuration(mTransitioner.getDuration(LayoutTransition.DISAPPEARING));
        mTransitioner.setAnimator(LayoutTransition.DISAPPEARING, removeAnimator);

        /**
         * view 動畫改變時,布局中的每個子view動畫的時間間隔
         */
        mTransitioner.setStagger(LayoutTransition.CHANGE_APPEARING, 30);
        mTransitioner.setStagger(LayoutTransition.CHANGE_DISAPPEARING, 30);


        /**
         *LayoutTransition.CHANGE_APPEARING和LayoutTransition.CHANGE_DISAPPEARING的過渡動畫效果
         * 必須使用PropertyValuesHolder所構造的動畫才會有效果,不然無效!使用ObjectAnimator是行不通的,
         * 發現這點時真特麼惡心,但沒想到更惡心的在後面,在測試效果時發現在構造動畫時,”left”、”top”、”bottom”、”right”屬性的
         * 變動是必須設置的,至少設置兩個,不然動畫無效,問題是我們即使這些屬性不想變動!!!也得設置!!!
         * 我就問您惡不惡心!,因為這裡不想變動,所以設置為(0,0)
         *
         */
        PropertyValuesHolder pvhLeft =
                PropertyValuesHolder.ofInt("left", 0, 0);
        PropertyValuesHolder pvhTop =
                PropertyValuesHolder.ofInt("top", 0, 0);
        PropertyValuesHolder pvhRight =
                PropertyValuesHolder.ofInt("right", 0, 0);
        PropertyValuesHolder pvhBottom =
                PropertyValuesHolder.ofInt("bottom", 0, 0);


        /**
         * view被添加時,其他子View的過渡動畫效果
         */
        PropertyValuesHolder animator = PropertyValuesHolder.ofFloat("scaleX", 1, 1.5f, 1);
        final ObjectAnimator changeIn = ObjectAnimator.ofPropertyValuesHolder(
                this, pvhLeft,  pvhBottom, animator).
                setDuration(mTransitioner.getDuration(LayoutTransition.CHANGE_APPEARING));
        //設置過渡動畫
        mTransitioner.setAnimator(LayoutTransition.CHANGE_APPEARING, changeIn);


        /**
         * view移除時,其他子View的過渡動畫
         */
        PropertyValuesHolder pvhRotation =
                PropertyValuesHolder.ofFloat("scaleX", 1, 1.5f, 1);
        final ObjectAnimator changeOut = ObjectAnimator.ofPropertyValuesHolder(
                this, pvhLeft, pvhBottom, pvhRotation).
                setDuration(mTransitioner.getDuration(LayoutTransition.CHANGE_DISAPPEARING));

        mTransitioner.setAnimator(LayoutTransition.CHANGE_DISAPPEARING, changeOut);
    }


    public void addView(View view) {
        i++;
        Button button = new Button(this);
        button.setText("布局動畫_" + i);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);
        container.addView(button, Math.min(1, container.getChildCount()), params);
    }

    public void removeView(View view) {
        if (i > 0)
            container.removeViewAt(0);
    }
}

??簡單分析一下,LayoutTransition.APPEARING和LayoutTransition.DISAPPEARING的情況下直接使用屬性動畫來設置過渡動畫效果即可,而對於LayoutTransition.CHANGE_APPEARING和LayoutTransition.CHANGE_DISAPPEARING必須使用PropertyValuesHolder所構造的動畫才會有效果,不然無效,真特麼惡心, ,但沒想到更惡心的在後面,在測試效果時發現在構造動畫時,”left”、”top”、”bottom”、”right”屬性的變動是必須設置的,至少設置兩個,不然動畫無效,最坑爹的是我們即使這些屬性不想變動!!!也得設置!!!我就問您惡不惡心!,那麼我們不想改變這四個屬性時該如何設置呢?這時只要傳遞的可變參數都一樣就行如下面的(0,0)也可以是(100,100)即可(坑爹啊!測試半天才發現,一直在考慮代碼有沒有問題,最後發現時特麼的也是醉了…….):

PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",0,0);  
PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("left",100,100);  
PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("bottom",0,0);  
PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("right",0,0);  

??還有點需要注意的是在使用的ofInt,ofFloat中的可變參數值時,第一個值和最後一個值必須相同,不然此屬性將不會有動畫效果,比如下面首位相同是有效的

PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",100,0,100);
PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("top",0,100,0);

但是如果是下面的設置就是無效的:

PropertyValuesHolder pvhTop = PropertyValuesHolder.ofInt("left",0,100);

??關於PropertyValuesHolder,後面我會分開單獨一篇來分析,這裡我們只需知道PropertyValuesHolder構造的動畫可以設置給ObjectAnimator.ofPropertyValuesHolder()便可以產生響應的動畫效果即可,該方法原型如下:

public static ObjectAnimator ofPropertyValuesHolder(Object target, PropertyValuesHolder... values)

??最後我們通過setAniamtor的方法設置LayoutTransition的5種狀態下的過渡動畫,最後運行一下程序,效果如下:
\
最後這裡小結一下LayoutTransition的一些常用函數:

函數名稱 說明 setAnimator(int transitionType, Animator animator) 設置不同狀態下的動畫過渡,transitionType取值為, APPEARING、DISAPPEARING、CHANGE_APPEARING、CHANGE_DISAPPEARING 、CHANGING setDuration(long duration) 設置所有動畫完成所需要的時長 setDuration(int transitionType, long duration) 設置特定type類型動畫時長,transitionType取值為, APPEARING、DISAPPEARING、CHANGE_APPEARING、CHANGE_DISAPPEARING 、CHANGING setStagger(int transitionType, long duration) 設置特定type類型動畫的每個子item動畫的時間間隔 ,transitionType取值為: APPEARING、DISAPPEARING、CHANGE_APPEARING、CHANGE_DISAPPEARING、CHANGING setInterpolator(int transitionType, TimeInterpolatZ喎?/kf/ware/vc/" target="_blank" class="keylink">vciBpbnRlcnBvbGF0b3IpPC9jb2RlPjwvY29kZT48L3RkPg0KCTx0ZD48Y29kZT48Y29kZT7J6NbDzNi2qHR5cGXA4NDNtq+7rbXEsuXWtcb3LCB0cmFuc2l0aW9uVHlwZcih1rXOqjogQVBQRUFSSU5HoaJESVNBUFBFQVJJTkehokNIQU5HRV9BUFBFQVJJTkehokNIQU5HRV9ESVNBUFBFQVJJTkehokNIQU5HSU5HPC9jb2RlPjwvY29kZT48L3RkPg0KCTwvdHI+DQoJPHRyPg0KCTx0ZD48Y29kZT48Y29kZT5zZXRTdGFydERlbGF5KGludCB0cmFuc2l0aW9uVHlwZSwgbG9uZyBkZWxheSk8L2NvZGU+PC9jb2RlPjwvdGQ+DQoJPHRkPjxjb2RlPjxjb2RlPsno1sPM2LaodHlwZcDg0M22r7uttcS2r7ut0dPKsSB0cmFuc2l0aW9uVHlwZcih1rXOqiwgQVBQRUFSSU5HoaJESVNBUFBFQVJJTkehokNIQU5HRV9BUFBFQVJJTkehokNIQU5HRV9ESVNBUFBFQVJJTkcgoaJDSEFOR0lORzwvY29kZT48L2NvZGU+PC90ZD4NCgk8L3RyPg0KCTx0cj4NCgk8dGQ+PGNvZGU+PGNvZGU+YWRkVHJhbnNpdGlvbkxpc3RlbmVyKFRyYW5zaXRpb25MaXN0ZW5lciBsaXN0ZW5lcik8L2NvZGU+PC9jb2RlPjwvdGQ+DQoJPHRkPjxjb2RlPjxjb2RlPsno1sO84Mz9xvdUcmFuc2l0aW9uTGlzdGVuZXI8L2NvZGU+PC9jb2RlPjwvdGQ+DQoJPC90cj4NCjwvdGJvZHk+DQo8L3RhYmxlPg0KPHA+PGNvZGU+PGNvZGU+udjT2rzgzP3G973Tv9pUcmFuc2l0aW9uTGlzdGVuZXLUrdDNyOfPwqO6PC9jb2RlPjwvY29kZT48L3A+DQo8cHJlIGNsYXNzPQ=="brush:java;"> /** * This interface is used for listening to starting and ending events for transitions. */ public interface TransitionListener { /** * 監聽LayoutTransition當前對應的transitionType類型動畫開始 * @param transition LayoutTransition對象實例 * @param container LayoutTransition綁定的容器-container * @param view 當前在做動畫的View對象 * @param transitionType LayoutTransition類型,取值有:APPEARING、DISAPPEARING、 * CHANGE_APPEARING、CHANGE_DISAPPEARING、CHANGING */ public void startTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType); /** * 監聽LayoutTransition當前對應的transitionType類型動畫結束 * @param transition LayoutTransition對象實例 * @param container LayoutTransition綁定的容器-container * @param view 當前在做動畫的View對象 * @param transitionType LayoutTransition類型,取值有:APPEARING、DISAPPEARING、 * CHANGE_APPEARING、CHANGE_DISAPPEARING、CHANGING */ public void endTransition(LayoutTransition transition, ViewGroup container, View view, int transitionType); }

??注釋比較清晰,就不過多說明,我們如果想在某種transitionType類型動畫開或者結束時設置某些操作,便可實現該接口,測試效果也比較簡單,這裡就不舉例了。ok~,關於布局動畫就先了解這麼多吧。

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