ViewFlipperでObjectAnimatorを使う

# はじめに

今回作りたいやつはこんなやつ。
<img src="https://qiita-image-store.s3.amazonaws.com/0/106116/479a2d9a-9fd1-701a-b348-26fe6f8a5c90.gif" width=50%>
ViewFlipperで表面、裏面を切り替える際、シンプルなアニメーション（ViewAnimator）ではなくObjectAnimatorのようなリッチなアニメーションを使いたい…
でもAdapterViewFlipperは実装が大変。。

実はちょっと工夫することで簡単にObjectAnimatorを使うことが出来ます。

# 実装
```xml:activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<ViewFlipper
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/flipper"
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="500dp"
        android:padding="30dp">
    <!-- 表面のレイアウト -->
    <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#ffaaaa">
        <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Hello World!"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintTop_toTopOf="parent"/>
    </androidx.constraintlayout.widget.ConstraintLayout>
    <!-- 裏面のレイアウト -->
    <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:background="#aaffaa">
        <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Hello World!の裏"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintRight_toRightOf="parent"
                app:layout_constraintTop_toTopOf="parent"/>
    </androidx.constraintlayout.widget.ConstraintLayout>
</ViewFlipper>
```

```kotlin:MainActivity.kt
class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 消えるときのアニメーション
        val outRotationY = ObjectAnimator.ofFloat(flipper, "rotationY", 0f, 90f)
        // 現れるときのアニメーション
        val inRotationY = ObjectAnimator.ofFloat(flipper, "rotationY", 270f, 360f)

        outRotationY.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator?) {
                // 消えるアニメーションが終了したタイミングで現れるアニメーションを実行
                inRotationY.start()
                // ViewFlipperの裏面レイアウトの表示を行う
                flipper.showNext()
            }
        })

        // flipperをタップしたら消えるアニメーションを実行する
        flipper.setOnClickListener {
            outRotationY.start()
        }
    }
}
```

以上を実装することで最初のGifアニメが再現できます。

# その他アニメーション
前述のアニメーションは上下の幅をとってしまい、見栄えが悪かったため実際のアプリではこちらのアニメーションを採用しました。よくあるカードをひっくり返すアニメーションです。

```kotlin:Main2Activity.kt
class Main2Activity : AppCompatActivity() {
    var isReversed = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        flipper.setOnClickListener {
            reverseCard(flipper, 1.0f, 0.0f, 1.0f, 1.0f)
            isReversed = true
        }
    }

    fun reverseCard(viewFlipper: ViewFlipper, vararg rotate: Float) {
        val scaleX = ObjectAnimator.ofFloat(viewFlipper, "scaleX", rotate[0], rotate[1])
        val scaleY = ObjectAnimator.ofFloat(viewFlipper, "scaleY", rotate[2], rotate[3])
        val animatorSet = AnimatorSet()
        animatorSet.interpolator = LinearInterpolator()
        animatorSet.playTogether(scaleX, scaleY)
        animatorSet.duration = 200
        animatorSet.addListener(object : AnimatorListenerAdapter() {
            override fun onAnimationEnd(animation: Animator?) {
                if (!isReversed) return

                reverseCard(viewFlipper, 0.0f, 1.0f, 1.0f, 1.0f)
                isReversed = false
                viewFlipper.showNext()
            }
        })
        animatorSet.start()
    }
}
```
<img src="https://qiita-image-store.s3.amazonaws.com/0/106116/1a157876-bf8d-a484-2a27-31249e1e6bd1.gif" width=50%>


# 最後に
いかがでしょうか？
皆様もよきアニメーションライフを。