素人からAndroidアニメーションの面白さを発見しよう

この記事は [リクルートライフスタイル Advent Calendar 2016](http://qiita.com/advent-calendar/2016/recruitlifestyle) の19日目の記事です。
#はじめに
こんにちは。[ホットペーパグルメ](https://www.hotpepper.jp/app)でアンドロイド開発を担当しているビン（Bing）です。中国出身で本名は朱冰凝（シュヒョウギョウ）ですが、名前の発音が難しくて自分も読みづらいのでビン（Bing）と読んでくれたら嬉しいです。
捜索エンジン[Bing](https://www.bing.com/)と関連がありませんけど…w
今回は私の初めての日本語ブログです。日本語でも技術についてでも、気兼ねなくコメントをくださいm(= =)m。

最近アニメーションをホットペッパーアプリに追加したら、アプリの温度感が凄く良くなった気がしています。

![ezgif.com-video-to-gif (7).gif](https://qiita-image-store.s3.amazonaws.com/0/147053/4f0e5e97-dfbc-1414-fa05-64a6a970fd0c.gif)



それで、Androidアニメーションでなにができるか、なんの面白い機能があるのかを調査したので、説明して行きたいと思います。

一般的にAndroidアニメーションはView AnimationとProperty Animation二種類です。名前を見ると、View AnimationはView（見た目）の変更で、簡単に使えるアニメーションです。Property Animationはpropertyの変更で、interactionともっとflexiableなアニメーションをカスタムできます。
# View Animation---古くてもまだ使いやすい
簡単なView変更のアニメーションならView Animationがオススメです。
Animation frameworkとして、透明度（alpha）、回転（rotate）、サイズ変更（scale）、位置変更（translate）四つのアニメーションを提供しています。繰り返してTransformationViewのvalueを変更してviewを描き続けるアニメーションを実現します。
 .xml fileでもjava fileでもかけます。
では簡単に透明度アニメーションのサンプルを書いてみました。

```xml:alpha_animation.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="5000">
    <alpha
        android:fromAlpha="0.0f"
        android:toAlpha="1.0f"
        />
</set>
```
```java:alpha_animation.java
AlphaAnimation aa = new AlphaAnimation(0, 1);
aa.setDuration(5000);
view.startAnimation(aa);
```

- メリット： 超わかりやすい、書きやすいコードです。 CPUも比較的抑えられて使えます。
- デメリット：interactionできないです。 アニメーションの順番の指定ができないです。

↑二つのデメリットのせいで、View Animationは複雑なアニメーションをすることが出来ません。 だからもっとFlexibleなProperty Animationをメインで紹介していきたいと思います。
#Property Animation---カスタム最強
Property Animationは新しいanimator frameworkを使って、Viewの見た目だけ変えるのではなく、propertyも変えてくれるので、よりinteractionなアニメーションを提供してくれます。 
例えば、アニメーションでViewの位置が変更された後でも変更先でクリックをすることができます。（それはView Animationできない特徴です。）
ちなみに、property animationはCPUを使いすぎないように、自動的にframe rateを調整できます。 
一般的にObjectAnimatorとAnimatorSetは合わせて使われていて、propertyを細かく調整できるので、デザイナーさんの意見にもFlexibleに対応することが出来ます。
## ObjectAnimator---Animatorを支配してる王様です！
ObjectAnimatorを使うと、カスタムアニメーションがほぼできます。
View Animationと同じように、透明度、サイズなどのpropertyを提供してくれます：

- relative位置変更： translationX & translationY
- absolutive位置変更： x, y
- 回転：rotation, rotationX, rotationY
- サイズ変更：scaleX, scaleY
- 回転またはサイズ変更の時の支点：pivotX, pivotY
- 透明度：alpha

.xmlでも.javaでもかけます。 
例えば湯気のアニメーションは.xmlで書きました。 setとobjectAnimatorを合わせて利用して、 透明度を薄くしていくアニメーションとサイズ（x, y）が大きくなるアニメーションを同時に変更するように指定しています。湯気がどんどん拡大する状態を表現できます。

```xml:yuge_animator.xml
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:ordering="together"
    android:startOffset="1000">
    <set android:ordering="together">
    <objectAnimator
        android:duration="6000"
        android:propertyName="scaleX"
        android:valueFrom="1.0"
        android:valueTo="10.0" />
    <objectAnimator
        android:duration="6000"
        android:propertyName="scaleY"
        android:valueFrom="1.0"
        android:valueTo="10.0"/>
    </set>
    <set>
    <objectAnimator
        android:duration="6000"
        android:propertyName="alpha"
        android:valueFrom="0.8"
        android:valueTo="0.01"/>
    </set>
</set>
```

一方、.javaで落ちるアニメーションのコードはこうなっています。 落ちる様子を自然にするため、位置変更（x, y）と回転(rotation, rotationY)を同時に指定しています。： 
*p.s. javaの方はもっとflexible：
- valueTo, valueFrom: .xmlは数字だけで、javaはvalueで指定できます。
- setの順番：.xmlはandroid:orderingはtogether, sequentiallyだけで、javaはAnimatorSetを利用したらカスタム順番指定できます。*

```java:fall_animator.java
ObjectAnimator animatorX1=ObjectAnimator.ofFloat(view, "x", mScreenWidth*x1);
ObjectAnimator animatorY1=ObjectAnimator.ofFloat(view, "y", mScreenHeight*y1);
ObjectAnimator rotation1=ObjectAnimator.ofFloat(view, "rotation", 180+new Random().nextInt(180));
ObjectAnimator rotation1_2=ObjectAnimator.ofFloat(view, "rotationY", 0, 180+new Random().nextInt(180));

AnimatorSet set=new AnimatorSet();
set.setDuration(2000+new Random().nextInt(3000));
set.playTogether(animatorX1, animatorY1, rotation1, rotation1_2);
```

##Property Animationのサプライズ機能
###Animator Set---どんな組み合わせもできる
複数個のアニメーションがある場合、順番の指定が必要です。 
AnimatorSetはflexibleに同時、先行、後行を指定できます。 AnimatorSetは順番指定のメソッドが多いです。e.g. playTogether(), playSequentially(), animSet.Play().with().after().before()とか… 
例えば、もっと自然な落ちるアニメーションは、三段に分かれていて、毎段位置、回転のrandom変更があります：

```java:fall_animatorSet.java
AnimatorSet set=new AnimatorSet();
set.setDuration(2000+new Random().nextInt(3000))
set.playTogether(animatorX1, animatorY1, rotation1, rotation1_2);
set.playTogether(animatorX2, animatorY2, rotation2, rotation2_2);
set.playTogether(animatorX3, animatorY3, rotation3, rotation3_2);
set.play(animatorX2).after(animatorX1).before(animatorX3);
set.start();
```
###ValueAnimator---アニメーションじゃないのに、Animator後ろのクイーンです！
ValueAnimatorはProperty Animationのコアです。
実はValueAnimator自身はアニメーションを提供してなく、ただ数値を続けて変更しているクラスです。ObjectAnimatorもValueAnimatorの子クラスとして、その変更してる数値を受け取りつつ、アニメーションを変更していきます。
位置Yアニメーションを例として、以下の通りです。

```java:valueAnimator.java
private void setAnimator() {
        ValueAnimator colorAnimator = ValueAnimator.ofInt(0, 1400);
        colorAnimator.setDuration(10000).start();
        colorAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                // 続けて変更してる数値を受け取る
                int height = (int) animation.getAnimatedValue();
                animatorButton.setY(height);
                heightText.setText("height is "+height);
            }
        });
    }
```

![ezgif.com-video-to-gif (8).gif](https://qiita-image-store.s3.amazonaws.com/0/147053/6a31797e-dfcf-0b4e-72ef-86ecce951019.gif)

ValueAnimatorの意味は、毎回変更したanimation.getAnimatedValue()を取得して、いろんなところで利用できます。
 e.g. 色の漸進的変化とか…
###Interpolators---アニメーションのプロなら使いやがれ！
より自然なアニメーションを実現するためには0から1に変化するアニメーションじゃなくて、変化のスピートによって値を変えていきます。それを実現させるためにandroidはいろんなInterpolatorを提供しています。例えば、落ちて跳ねるアニメーションはBounceInterpolatorで表現できます。

```xml:interpolator_animator.xml
<set >
    <objectAnimator
        android:duration="3000"
        android:propertyName="translationY"
        android:valueFrom="5"
        android:valueTo="1500"
        android:interpolator="@android:anim/bounce_interpolator">
    </objectAnimator>
</set>
```

[Interpolatorsイメージ](http://www.adakoda.com/adakoda/2011/08/android-38.html)の図と合わせて見ると理解しやすいです。 
自分よく使ってるInterpolatorは加速と減速です、スピードの変更はこんな感じです： 
![image](https://qiita-image-store.s3.amazonaws.com/0/147053/d42fcb24-56b7-f5f3-2c9b-a4f029e2612e.png)![image](https://qiita-image-store.s3.amazonaws.com/0/147053/7d6d629b-88d6-1c29-2e6b-c04f644370f5.png)
  *AccelerateInterpolator　　　　   DecelerateInterpolator*
上に話したちょっと複雑なInterpolatorはこんな感じです。動きかたはmaterial designの定義と合っているので、使うと間違いなしです。
![image](https://qiita-image-store.s3.amazonaws.com/0/147053/ac8198fc-ca80-12a4-056a-4a00343d1208.png)![image](https://qiita-image-store.s3.amazonaws.com/0/147053/31c2d0a3-08c5-6610-6699-24ad9965b8a6.png)
*BounceInterpolator　　　　    OvershootInterpolator*
#終わりに
同じホットペーパ開発チームweb担当の小山さん(神)が書いたAdvent Calendar8日目の記事（[美術が「２」だったEngineerでも作れるCSS アニメーション](http://qiita.com/myamyu/items/318ee8ac83b8ec1a8c80)）はすごく気になって、自分もAndroidでアニメーションで柚子湯を作って見ました。
（柚子落ちは回転＋位置変更＋BounceInterpolatorアニメーションで、湯気はサイズ拡大＋透明度のアニメーションです）
![ezgif.com-video-to-gif (6).gif](https://qiita-image-store.s3.amazonaws.com/0/147053/1b161ab2-589c-6962-336a-acb857aa8d82.gif)


それで、クリスマスが近づきますので、サンタおじさんを迎えるためにこんなものも作りました＞＜： 
（位置変更＋回転アニメーションで）
![ezgif.com-optimize (1).gif](https://qiita-image-store.s3.amazonaws.com/0/147053/841c16fe-384f-5fdf-5db6-c1116ef0eac6.gif)



#参考資料
1. [google公式ページ：animation-resource](https://developer.android.com/guide/topics/resources/animation-resource.html)
2. [Android heroes](https://www.amazon.cn/%E5%9B%BE%E4%B9%A6/dp/B01481RAA4)