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

## 概要

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

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

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

![ezgif-5-3c902af560.gif](https://qiita-image-store.s3.amazonaws.com/0/88858/b9495181-7eef-f698-9370-127fb3c89402.gif)

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


## 拡大/縮小

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


![ezgif-5-c3e1e0c736.gif](https://qiita-image-store.s3.amazonaws.com/0/88858/ef7fff28-7018-bc7e-60dc-3cc505ac1f16.gif "ezgif-5-c3e1e0c736.gif")

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

```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: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()](https://developer.android.com/reference/android/animation/LayoutTransition.html#enableTransitionType(int))に[CHANGING](https://developer.android.com/reference/android/animation/LayoutTransition.html#CHANGING)をセットします。

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

>[enableTransitionType()](https://developer.android.com/reference/android/animation/LayoutTransition.html#enableTransitionType(int))はAPI Level 16から追加された事に注意してください。

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

![ezgif-5-616171dffc.gif](https://qiita-image-store.s3.amazonaws.com/0/88858/8b0beef6-2d14-a62f-855c-24fc19a68d8a.gif "ezgif-5-616171dffc.gif")



## 注意点

[追加/削除/表示/非表示](https://qiita.com/aroe_lemon/items/87dfb14d44a808572042#%E8%BF%BD%E5%8A%A0%E5%89%8A%E9%99%A4%E8%A1%A8%E7%A4%BA%E9%9D%9E%E8%A1%A8%E7%A4%BA)で使用したレイアウトは下記になります。

```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: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"```を設定してみてください。

[ドキュメント](https://developer.android.com/reference/android/animation/LayoutTransition.html)にもありますが、ネストされた複数の階層でViewをアニメーションをさせると機能しない場合があるようです。

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