思い通りにAnimated Vector Drawableを動かすには

# やりたいこと

romannurik氏の神ツール、[AndroidIconAnimator](https://romannurik.github.io/AndroidIconAnimator/) を使って、

下向き矢印 expand more ![expand-more](https://github.com/google/material-design-icons/raw/master/navigation/2x_web/ic_expand_more_black_48dp.png) を
上向き矢印 expand less ![expand-less](https://github.com/google/material-design-icons/raw/master/navigation/2x_web/ic_expand_less_black_48dp.png) に変形させたい。

:point_down: こんな感じに。

![ezgif.com-267fcec6cb.gif](https://qiita-image-store.s3.amazonaws.com/0/41896/942900b3-0a85-44bd-1bf3-768d6ecf1df0.gif)


# 材料

* [AndroidIconAnimator](https://romannurik.github.io/AndroidIconAnimator/)
    * ツールの使い方についてはtakahiromさんの記事を参考に -> [アニメーションアイコンが作れるAndroid Icon Animatorを触ってみる](http://qiita.com/takahirom/items/3deee8b73e0a2bc1a50b)
* [Material Icons](https://material.io/icons/)のアイコン
    * 下向き矢印 `expand more`
    * 上向き矢印 `expand less`


# ハマる

初めは単純に以下のことをやりました。

1. SVG形式でダウンロードしてきた `expand more` を AndroidIconAnimator に D&D でインポート
2. pathData アニメーションを追加
3. toValue に `expand less` のSVGのパスデータをコピペ

[その時点でのiconanimファイルはこちら。](https://gist.github.com/kikuchy/f1c08596e8a35deb70f6cab50f03dc31#file-before-iconanim)

これで、 **開始時点では `expand more`、終了時点では `expand less` のアニメーション** が出来上がるはず。

![ezgif.com-b38f62c148.gif](https://qiita-image-store.s3.amazonaws.com/0/41896/bb8c15dd-e514-9baf-027e-7c3d7e110c44.gif)

( ﾟдﾟ) 何かが違う…


# ハマりどころと回避方法

## （前提として）パスデータのコマンド数を合わせる

[こにふぁーさんのスライド](https://speakerdeck.com/konifar/what-you-should-know-about-animatedvectordrawable)でも言われている通り、パスデータのコマンドの数が、 fromValue と toValue で一致している必要があります。

Material Iconsの `expand more` と `expand less` の場合はコマンド数が一致していたので無問題でした。


# コマンドの順番を合わせる

できたアニメーションをよく観察すると、 `expand more` で右上にある点が `expand less` の矢印の頂点になっていることがわかります。

![Android_Icon_Animator.png](https://qiita-image-store.s3.amazonaws.com/0/41896/5aa2da28-e665-171e-7ea8-4077202095a1.png)
![Android_Icon_Animator 2.png](https://qiita-image-store.s3.amazonaws.com/0/41896/7bf25368-b35a-92d9-5615-8a7f60b2fbd8.png)


両方のSVGのパスデータも見てみましょう。
コマンドごとに改行を入れています。

```
<!-- expand more -->
M16.59 8.59
L12 13.17
 7.41 8.59
 6 10
l6 6
 6-6
z


<!-- expand less -->
M12 8
l-6 6
 1.41 1.41
L12 10.83
l4.59 4.58
L18 14
z
```

始めの `M` コマンドの座標が、 `expand more` では `16.59 8.59`（右上）、 `expand less` では `12 8`（中央一番上）。

どうやら、 **パスデータに出現するコマンドの順によって fromValue と toValue で対応する点を決定している** ようです。

とすれば、 `expand more` のコマンドの順番と `expand less` の各コマンドが指定する座標がわかれば、 `expand more` の各頂点と期待通りに対応する `expand less` を描画する事ができそうです。

`expand more` の座標を指定するコマンドの順は以下の通りでした。

![Cursor_と_Android_Icon_Animator.png](https://qiita-image-store.s3.amazonaws.com/0/41896/722211dc-9c81-74c1-9837-dce1203e7a7a.png)

また、 `expand less` の各頂点の座標は以下の通り。

![Android_Icon_Animator 3.png](https://qiita-image-store.s3.amazonaws.com/0/41896/05e6ac57-f867-638f-505d-8a43d215f30b.png)


完成イメージ通りに動かしたい場合は、 `18 14` から逆時計回りに描画していけば良さそうだということがわかります。

さて、これでアニメーションしてみると

![ezgif.com-46f4ec83a3.gif](https://qiita-image-store.s3.amazonaws.com/0/41896/9fbdd15e-47d8-ba62-a20b-01461c8a7232.gif)

なんだか太ましい…


# 期待通りにモーフィングしなかったら中割りを入れる

[中割りについてはニコニコ大百科が詳しいのでそちらを御覧ください](http://dic.nicovideo.jp/a/%E4%B8%AD%E5%89%B2%E3%82%8A)。

今回のアニメーションでは一度棒状になって欲しいので、タイムラインの中間地点でアニメーションを区切ることにしました。

全体では以下のようなアニメーションなので、

* 時間 ... 0.6秒
* Interpolator ... Accelerate/Decelerate 

以下のように分割しました。

```
0.0s               0.3s               0.6s
[expand more] ---> [棒] ---> [expand less]
      Accelerate           Decelerate
```

![ezgif.com-267fcec6cb.gif](https://qiita-image-store.s3.amazonaws.com/0/41896/942900b3-0a85-44bd-1bf3-768d6ecf1df0.gif)

できた！　さあ実機で動かそう！

:point_down: 

```
android.view.InflateException:  Can't morph from ... to ...
```

( ﾟдﾟ)


# AnimatedVectorDrawableのパスデータではコマンド表記を省略できない

SVGですと、線描画 `L` を続けて書きたい場合は、２つ目以降の座標ではコマンドを省略して書くことができます。

```
<!-- SVGなら大丈夫だがAVDではだめ -->
L10 10
 15 20
 30 12
 ...
```

AndroidのAnimatedVectorDrawableではコマンドが省略できないらしく、各座標にコマンドを明記する必要があるようです。

```
<!-- AVDでも大丈夫 -->
L10 10
L15 20
L30 12
 ...
```

省略されていたコマンドを明記してやることで、無事に動作させることができました。 :tada: 


AndroidIconAnimatorではアニメーションの描画にcanvasを使っており、パスデータはブラウザが解釈できるものであればエラーなど出さずに動いてしまうようです。
SVGを D&D してインポートした際にはAVDで解釈できる形式にコンバートしてくれるようですが、人手でパスデータを操作する際には注意が必要そうです。