Android

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

More than 1 year has passed since last update.

やりたいこと

romannurik氏の神ツール、AndroidIconAnimator を使って、

下向き矢印 expand more expand-more
上向き矢印 expand less expand-less に変形させたい。

:point_down: こんな感じに。

ezgif.com-267fcec6cb.gif

材料

ハマる

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

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

その時点でのiconanimファイルはこちら。

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

ezgif.com-b38f62c148.gif

( ゚д゚) 何かが違う…

ハマりどころと回避方法

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

こにふぁーさんのスライドでも言われている通り、パスデータのコマンドの数が、 fromValue と toValue で一致している必要があります。

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

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

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

Android_Icon_Animator.png
Android_Icon_Animator 2.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

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

Android_Icon_Animator 3.png

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

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

ezgif.com-46f4ec83a3.gif

なんだか太ましい…

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

中割りについてはニコニコ大百科が詳しいのでそちらを御覧ください

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

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

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

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

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

ezgif.com-267fcec6cb.gif

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

:point_down:

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

( ゚д゚)

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

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

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

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

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

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

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