Android

LayoutTransition:お手軽にアニメーション

概要

LayoutTransitionはViewGroupのレイアウト変更によるアニメーションを自動的にやってくれるクラスです。
ちなみにAPI Level 11から追加されています。
使い方は、LayoutTransitionを生成して、アニメーションさせたいViewGroupにsetLayoutTransition(LayoutTransition)します。
レイアウトファイルで設定する場合は、ViewGroupの属性にandroid:animateLayoutChanges="true"をセットするだけです。
これだけで、ViewGroupに子Viewが追加/削除/表示/非表示された時にアニメーションするようになります。

追加/削除/表示/非表示

デフォルトではViewが追加/削除/表示/非表示された時にアニメーションが実行されます。
こちらがデフォルトのアニメーションです。

ezgif-5-3c902af560.gif

Viewを追加する場合は先に他のViewが移動した後に新しいViewがフワッと追加されます。
Viewを削除する場合は逆に消されるViewがフワッと消えてから他のViewが動きます。
Viewを表示(Visible)/非表示(Gone)した場合は、追加/削除されたViewと同じアニメーションになります。

拡大/縮小

では、Viewが拡大/伸縮した場合はどうなるのでしょうか?

ezgif-5-c3e1e0c736.gif

Viewが拡大/縮小されてもアニメーションしないですね。
拡大/縮小させるFrameLayout(@id/text_layout)にandroid:animateLayoutChanges="true"をセットしているのにも関わらずアニメーションされませんでした。

<?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:animateLayoutChanges="true"
    android:gravity="center_horizontal"
    android:orientation="vertical">

    <FrameLayout
        android:id="@+id/text_layout"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        android:animateLayoutChanges="true"
        android:background="#ff6f6f">

        <TextView
            android:id="@+id/text_view"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:padding="10dp" />
    </FrameLayout>

    <EditText
        android:id="@+id/edit_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <Button
        android:id="@+id/submit"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="submit" />

</LinearLayout>

上述したとおり、デフォルトでは追加/削除/表示/非表示された時のみしかアニメーションが実行されないからです。
拡大/縮小のアニメーションを設定するためにはenableTransitionType()CHANGINGをセットします。

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
    ((ViewGroup) findViewById(R.id.text_layout)).getLayoutTransition()
            .enableTransitionType(LayoutTransition.CHANGING);
}

enableTransitionType()はAPI Level 16から追加された事に注意してください。

これでViewが拡大/縮小された場合でもアニメーションするようになりました。

ezgif-5-616171dffc.gif

注意点

追加/削除/表示/非表示で使用したレイアウトは下記になります。

<?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:animateLayoutChanges="true"
    android:orientation="vertical">


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <Button
            android:id="@+id/add_button"
            android:layout_width="0dp"
            android:layout_height="40dp"
            android:layout_margin="3dp"
            android:layout_weight="1"
            android:background="#ffc6c6"
            android:gravity="center"
            android:text="Add" />

            ・・・・・

    </LinearLayout>

    <LinearLayout
        android:id="@+id/container"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"
        android:animateLayoutChanges="true"
        android:orientation="vertical" />

    <FrameLayout
        android:id="@+id/bottom_view"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:animateLayoutChanges="true"
        android:background="#37e4ae">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="Item"
            android:textColor="@android:color/white" />
    </FrameLayout>

</LinearLayout>

android:animateLayoutChanges="true" がルートのViewGroupとFrameLayout(@id/bottom_view)に設定されていますね。
ルートのViewGroupにandroid:animateLayoutChanges="true"を設定しなかった場合はVisible/Goneのアニメーションはしなくなります。
ADD/REMOVEボタンをタップした時にViewが追加/削除されるLinearLayout(@id/container)はルートのViewGroupにandroid:animateLayoutChanges="true"を設定しなくてもアニメーションします。

どういった時に必要なのかは分かりませんが、アニメーションしなかった場合はルートのViewGroupにandroid:animateLayoutChanges="true"を設定してみてください。

ドキュメントにもありますが、ネストされた複数の階層でViewをアニメーションをさせると機能しない場合があるようです。

おわりに

ViewGroupの属性にセットするだけでアニメーションをつけられるお手軽感はありますが、アニメーションが不安定だったり、Viewの構成によっては動かない場合があるので、あまりオススメできません。。。
シンプルな画面でコストをかけずにアニメーションを付けたい時などに使う程度ですね。