AndroidのアニメーションAPIまとめ 2018

Android Dev Summit 2018のセッション [Get Animated](https://www.youtube.com/watch?v=N_x7SV3I3P0) が、AndroidのアニメーションAPIのまとめとして素晴らしかったのですが、Googleのセッションの常として、YouTube動画はあるけれどスライド資料がなかったので、メモがてら要点をまとめました。

# アニメーションAPI一覧

| API名                                                 | APIレベル                                       |
| ----------------------------------------------------- | ----------------------------------------------- |
| [View Animations](#view-animations)                   | 1+                                              |
| [Value Animator](#value-animator)                     | 11+                                             |
| [Object Animator](#object-animator)                   | 11+                                             |
| [View Property Animator](#view-property-animator)     | 12+                                             |
| [Animated Vector Drawable](#animated-vector-drawable) | 21+ (AndroidXライブラリにより14+で利用可能[^1]) |
| [Physics](#physics) (AndroidX)                        | 14+[^2]                                         |
| [Transitions](#transitions)                           | 19+ (AndroidXライブラリにより14+で利用可能)     |
| [Motion Layout](#motion-layout) (AndroidX)            | 18+                                             |

# どのAPIを使うべきかの判断フロー

1. 複数のViewが関係する複雑なアニメーション、かつ、ユーザー操作に応じたアニメーション<br />→ [Motion Layout](#motion-layout)
2. 途中で中断する可能性がある、かつ、ユーザー操作に応じたアニメーション<br />→ [Physics](#physics)
3. Activity/Fragment遷移時のShared elementなど、ウィンドウ内容のアニメーション<br />→ [Transitions](#transitions)
4. ベクター画像のアニメーション<br />→ [Animated Vector Drawable](#animated-vector-drawable)
5. ウィンドウ全体のアニメーション<br />→ [View Animations](#view-animations)
6. Viewプロパティのアニメーション<br />→ [View Property Animator](#view-property-animator)
7. Viewプロパティ以外のカスタムアニメーション[^3]<br />→ [Value Animator](#value-animator)
8. 汎用的なプロパティアニメーション<br />→ [Object Animator](#object-animator)

# View Animations

- [android.view.animation](https://developer.android.com/reference/android/view/animation/package-summary)
- ViewのDrawパスで実行されるので、必ずViewのサイズが計測済みの状況で実行される、という特徴がある
  - そのため、`10%` などの相対サイズ表現が使える
- リソースXMLは `res/anim` フォルダに配置する

  ```xml
  <set xmlns:android="http://schemas.android.com/apk/res/android"
       android:shareInterpolator="false">
      <translate
          android:fromYDelta="0"
          android:toYDelta="-2%"
          android:interpolator="@interpolator/fast_out_slow_in"
          android:duration="425"/>
      <alpha
          android:fromAlpha="1.0"
          android:toAlpha="0.9"
          android:interpolator="@interpolator/linear"
          android:duration="117"/>
  </set>
  ```

- 以下のケースで必要になるが、それ以外では使う必要はない
  - Windowアニメーション
  - Fragmentアニメーション (サイズの計測後に開始する必要があるアニメーションだけ)

# Animator

- [android.animation](https://developer.android.com/reference/android/animation/package-summary)
- リソースXMLは `res/animator` フォルダに配置する
- Animator関連のAPIは、以下のような関係を持つ<br />
  ![Screen_Shot_2018-12-30_at_14_38_49.png](https://qiita-image-store.s3.amazonaws.com/0/80557/6b702b6d-3352-d290-5de3-60fc88ee4510.png)<br />
  ([Get Animated (Android Dev Summit '18) - YouTube](https://youtu.be/N_x7SV3I3P0?t=355) より)

## Value Animator

- [ValueAnimator](https://developer.android.com/reference/android/animation/ValueAnimator)
- オブジェクトのプロパティではない、独立した値を変化させて、アニメーションを実装するときに使う
- 変化前後の値や、アニメーション時間など、リソースXMLでは `animator` タグで定義できる

  ```xml
  <animator xmlns:android="http://schemas.android.com/apk/res/android"
      android:duration="1000"
      android:valueFrom="1"
      android:valueTo="0"
      android:valueType="floatType"
      android:repeatCount="1"
      android:repeatMode="reverse"/>
  ```

- コードでは、次のように定義・実行できる

  ```kotlin
  ValueAnimator.ofInt(0, 4).apply {
      repeatCount = 10
      duration = 1000
      addUpdateListener { valueAnimator ->
          val value = valueAnimator.animatedValue as Int
          // ...
      }
  }
  ```

## Object Animator

- [ObjectAnimator](https://developer.android.com/reference/android/animation/ObjectAnimator)
- Viewに限らず、何らかのオブジェクトのプロパティ変化で表現できるアニメーションの実装に使う
- 変化前後のプロパティ値や、プロパティの名前、アニメーション時間など、リソースXMLでは `objectAnimator` タグで定義できる

  ```xml
  <objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
      android:duration="1000"
      android:valueTo="200"
      android:valueType="floatType"
      android:propertyName="y"
      android:repeatCount="1"
      android:repeatMode="reverse"/>
  ```

- コードでは、次のように定義・実行できる

  ```kotlin
  ObjectAnimator.ofFloat(view, View.ALPHA, 1f, 0f).apply {
      duration = 100
  }.start()
  ```

- [`PropertyValuesHolder`](https://developer.android.com/reference/android/animation/PropertyValuesHolder) (APIレベル23+) を使うと、複数のプロパティを同時にアニメーションできる

  ```kotlin
  val scaleX = PropertyValuesHolder.ofFloat(View.SCALE_X, 0.5f, 1f)
  val scaleY = PropertyValuesHolder.ofFloat(View.SCALE_Y, 0.5f, 1f)
  val alpha = PropertyValuesHolder.ofFloat(View.ALPHA, 0f, 1f)
  
  ObjectAnimator.ofPropertyValuesHolder(view, scaleX, scaleY, alpha).apply {
      duration = 100
  }.start()
  ```

- [`AnimatorSet`](https://developer.android.com/reference/android/animation/AnimatorSet) を使うと、複数の [`Animator`](https://developer.android.com/reference/android/animation/Animator.html) を協調して実行できる

## View Property Animator

- [ViewPropertyAnimator](https://developer.android.com/reference/android/view/ViewPropertyAnimator)
- [`View.animate()`](https://developer.android.com/reference/android/view/View#animate()) で [`ViewPropertyAnimator`](https://developer.android.com/reference/android/view/ViewPropertyAnimator.html) のインスタンスを取得し、実行する

  ```kotlin
  view.animate()
      .scaleX(1f).scaleY(1f).alpha(1f)
      .setInterpolator(OvershootInterpolator())
      .start()
  ```

- 単一のViewに対して、シングルショットのアニメーションを実行する場合に向いている

# Animated Vector Drawable

- [AnimatedVectorDrawable](https://developer.android.com/reference/android/graphics/drawable/AnimatedVectorDrawable) (AndroidX: [AnimatedVectorDrawableCompat](https://developer.android.com/reference/androidx/vectordrawable/graphics/drawable/AnimatedVectorDrawableCompat))
- Vector DrawableとAnimatorをセットにしたもの。Vector Drawableのプロパティを、Animatorでアニメーションさせている
- Android 7.0 (APIレベル25) 以降では、アニメーションがUIスレッドでなくRenderスレッドで実行されるので、アニメーションのジャンクが起こりづらくなっている

# Physics

- [Physics-based motion](https://developer.android.com/training/animation/overview#physics-based)
- 慣性を考慮したアニメーションを実装するためのAPI<br />
  <img width="250" src="https://qiita-image-store.s3.amazonaws.com/0/80557/f9f53288-ca37-bff2-5c67-89858c1037a8.gif" /><br />
  ([Animations Overview  |  Android Developers](https://developer.android.com/training/animation/overview) より)

# Transitions

- [android.transition](https://developer.android.com/reference/android/transition/package-summary) (AndroidX: [androidx.transition](https://developer.android.com/reference/androidx/transition/package-summary))
- Viewレイアウトの変化をアニメーションさせるためのAPI
- Transitionの内容は、コードや、`res/transition` に配置するXMLで定義できる

  ```xml
  <transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
      android:transitionOrdering="sequential">
      <fade android:fadingMode="fade_out" />
      <changeBounds />
      <fade android:fadingMode="fade_in" />
  </transitionSet>
  ```

- Activity/Fragment遷移時に、ウィンドウの内容をアニメーションするときにも利用する<br />
  ![0_72H_VxsWtTQV17Su.gif](https://qiita-image-store.s3.amazonaws.com/0/80557/e5b93849-4a15-9083-2bfa-d9d5f3eb362b.gif)<br />
  ([Restitching Plaid – Nick Butcher – Medium](https://medium.com/@crafty/restitching-plaid-9ca5588d3b0a) より)

# Motion Layout  

- [MotionLayout](https://developer.android.com/reference/android/support/constraint/motion/MotionLayout)
- [MotionLayout](https://developer.android.com/reference/android/support/constraint/motion/MotionLayout) は [ConstraintLayout](https://developer.android.com/reference/android/support/constraint/ConstraintLayout.html) の派生クラス
- `ConstraintLayout` 内の子ViewのConstraint ([`ConstraintSet`](https://developer.android.com/reference/android/support/constraint/ConstraintSet)) を複数定義して、その間をなめらかにアニメーションすることができる<br />
  ![1_gT_lL-MVY41xI2sMWs7dEQ.gif](https://qiita-image-store.s3.amazonaws.com/0/80557/0828370a-f1c9-3295-c2d1-3b8310168eab.gif)<br />
  [(Introduction to MotionLayout (part III) – Google Developers – Medium](https://medium.com/google-developers/introduction-to-motionlayout-part-iii-47cd64d51a5) より)

[^1]: 古いバージョンのサポートライブラリを使えば、[APIレベル7+に遡ってサポート可能](https://developer.android.com/guide/topics/graphics/vector-drawable-resources#vector-drawables-backward-solution)です
[^2]: サポートしているバージョンに関する記述が見つからなかったので、全AndroidXライブラリの最低サポートバージョンであるAPIレベル14+が適用されると判断しました
[^3]: セッションではこの順序で紹介されていたのですが、7 (Value Animator) と8 (Object Animator) の順序が逆なのでは、と思います。つまり、まずObject Animatorが使えないか検討して、使えないケースでValue Animatorを使うことになるのかな、と