マテリアルデザインのアニメーション実装(Google製 Plaid) Part 1: 起動編

# Plaidとは
Google製のマテリアルデザインの参考実装のアプリです。結構アニメーションなどで参考になる点が多いです。
ちょっとどういう風にアニメーションって実装するのが普通なのかよくわからないので、読んでみたいなと思いました。

https://github.com/nickbutcher/plaid

アプリ自体は「Plaid - デザイナーなら使いたいAndroidアプリ」として紹介されたりなど普通に使えるものとなっています。
http://www.moongift.jp/2015/11/plaid-%E3%83%87%E3%82%B6%E3%82%A4%E3%83%8A%E3%83%BC%E3%81%AA%E3%82%89%E4%BD%BF%E3%81%84%E3%81%9F%E3%81%84android%E3%82%A2%E3%83%97%E3%83%AA/

普通に画面遷移とかのソースコードを読もうと思っていたのですが、その前に起動でもいろいろいやっていたので見てみました。


# 起動部分

起動するだけですが３つの表示が見て取れます。

![sample.gif](https://qiita-image-store.s3.amazonaws.com/0/27388/fbf68709-0403-e68f-0ee6-683d831ee3f9.gif)

* タイトルのアニメーション
* 最初の3種類の黒色画像表示
* 画像の色の彩度のアニメーション


# タイトルのアニメーション
![title.gif](https://qiita-image-store.s3.amazonaws.com/0/27388/96af24e1-0e4b-e7fe-264d-5239967f3576.gif)

最初からハックっぽいやつで申し訳ないです。。
コメントにあるように良くない実装ではあるのですが、ToolbarのTitleをgetChildAt(0)でタイトルのTextViewを取り出してアニメーションさせています。
アニメーションにはView Property Animationを利用しています。(結構これを使うと簡潔にかけて良いですね)
http://android-developers.blogspot.jp/2011/05/introducing-viewpropertyanimator.html

letterSpacingをアニメーションさせたかったようですがうまくアニメーション出来なかった用で大きさのアニメーションになっているようです。
getFastOutSlowInInterpolatorで取得しているのはAndroid 5.0以上で利用できるInterpolatorですが、Support LibraryにFastOutSlowInInterpolatorがあるのでそれで利用できます。

Activity#onCreateから呼び出して利用します。

```java
    private void animateToolbar() {
        // this is gross but toolbar doesn't expose it's children to animate them :(
        View t = toolbar.getChildAt(0);
        if (t != null && t instanceof TextView) {
            TextView title = (TextView) t;

            // fade in and space out the title.  Animating the letterSpacing performs horribly so
            // fake it by setting the desired letterSpacing then animating the scaleX ¯\_(ツ)_/¯
            title.setAlpha(0f);
            title.setScaleX(0.8f);

            title.animate()
                    .alpha(1f)
                    .scaleX(1f)
                    .setStartDelay(300)
                    .setDuration(900)
                    .setInterpolator(AnimUtils.getFastOutSlowInInterpolator(this));
        }
....
```

https://github.com/nickbutcher/plaid/blob/210dc82b9392d4f4999e1c87e6cfcd6a553f8270/app/src/main/java/io/plaidapp/ui/HomeActivity.java#L679-L679

# 最初の3種類の黒色画像

プログレスバーが終わったあとのアニメーションですが。
最初の黒い画像が何種類か出てきます。
フェードインのように見せるために必要？のようです。

![image](https://qiita-image-store.s3.amazonaws.com/0/27388/67d0e426-1218-8ce8-c2c5-529f59cdd678.png)

```java
// need both placeholder & background to prevent seeing through shot as it fades in
holder.image.setBackground(
                shotLoadingPlaceholders[position % shotLoadingPlaceholders.length]);
```
https://github.com/nickbutcher/plaid/blob/69fefeb683d0bc08aba45d7edea71c8927fb476c/app/src/main/java/io/plaidapp/ui/FeedAdapter.java#L390-L390

色の指定は以下のようになっているようです
![image](https://qiita-image-store.s3.amazonaws.com/0/27388/9a38cf29-a51a-334a-6e31-d84241b56e00.png)
https://github.com/nickbutcher/plaid/blob/bd64f9c3fce82ec2da1ee001f9aedf1f74a26533/app/src/main/res/values/colors.xml#L84-L84

# 色の彩度のアニメーション
画像の**色**にご着目ください。
![sample.gif](https://qiita-image-store.s3.amazonaws.com/0/27388/fbf68709-0403-e68f-0ee6-683d831ee3f9.gif)
こちらマテリアルデザインの**Loading images**にあるものになります。
https://material.google.com/patterns/loading-images.html

彩度(saturation)を変えてアニメーションさせています。
これはColorFilterを使って実現できるようです。

```java
holder.image.setHasTransientState(true);
final ObservableColorMatrix cm = new ObservableColorMatrix();
final ObjectAnimator saturation = ObjectAnimator.ofFloat(
        cm, ObservableColorMatrix.SATURATION, 0f, 1f);
saturation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener
        () {
    @Override
    public void onAnimationUpdate(ValueAnimator valueAnimator) {
        // just animating the color matrix does not invalidate the
        // drawable so need this update listener.  Also have to create a
        // new CMCF as the matrix is immutable :(
        holder.image.setColorFilter(new ColorMatrixColorFilter(cm));
    }
});
saturation.setDuration(2000L);
saturation.setInterpolator(getFastOutSlowInInterpolator(host));
saturation.addListener(new AnimatorListenerAdapter() {
    @Override
    public void onAnimationEnd(Animator animation) {
        holder.image.clearColorFilter();
        holder.image.setHasTransientState(false);
    }
});
saturation.start();
```


https://github.com/nickbutcher/plaid/blob/2105876e4acc4370f5b0f85bd0b29ce9aa1155bd/app/src/main/java/io/plaidapp/ui/FeedAdapter.java#L349-L349

# 下位互換性について
APIレベル的にはView#setHasTransientState()がAPI Level 16(Android 4.1)でしたが、ViewCompatにもあり、呼ばなくてもこちらは特に問題にならないので普通にAPI Level 15(Android 4.0.3)以上などにしていれば問題なく動きそうです(ちゃんとは検証できていません。)

# かんたんに確認するには

Plaidは結構でかいアプリなので、アニメーションの部分だけのコードを抜き出して作ってみました。(今は起動部分のみ)
また一応Support Libraryに置き換えを行っているのでAndroid 4.0でも動くはずです。
https://github.com/takahirom/PlaidAnimation
![sample.gif](https://qiita-image-store.s3.amazonaws.com/0/27388/4f3de22a-b15e-cb4a-eb76-db59d495f695.gif)

# シリーズ追加しました
マテリアルデザインのアニメーション実装(Google製 Plaid) Part 2: Ripple + Elevation
http://qiita.com/takahirom/items/2e67333adecb189dbc93