Android Icon Animatorを活用してアニメーションリソース軽量化

Androidエンジニアの@nissiyです。Androidでは、API Level 21からベクター画像をアニメーションさせる仕組みであるAnimatedVectorDrawableが使えるようになりました。また、Support Libraryのv23.2.0からはAnimatedVectorDrawableCompatが提供され、API Level 11からも使えるようになりました。
これらは、1つのリソースファイルで拡大縮小に強いアニメーションが作れる優秀な仕組みになっていますが、使うためには animated-vector タグで囲った入り組んだリソースファイルを作成する必要があります。
しかし、先日GoogleのRoman NurikさんによってAndroid Icon Animatorという、AnimatedVectorDrawableとAnimatedVectorDrawableCompatで使えるリソースファイルをWebブラウザ上で作成できるオーサリングツールが作られました。 現在はプレビューリリースということですが機能は十分に揃っているのでぜひともチェックしてみてください。

f:id:vasilyjp:20161026181807p:plain

今回はiQON内の多くの箇所で使用しているアニメーション付きのLIKEボタンをAndroid Icon Animatorで作り直した工程を紹介したいと思います。

Android Icon Animatorの基本的な使い方

Android Icon Animatorの基本的な使い方を理解したい方は@takahiromさんの記事がスゴくオススメです。

qiita.com

ぜひとも本稿とあわせて読んでみてください。

今までのアニメーション付きのLIKEボタンについて

今までのLIKEボタンは、17枚の画像を使用したFrameアニメーションになっています。

f:id:vasilyjp:20161026181830g:plain

iQONでは、hdpi・xhdpi・xxhdpiのリソース画像を設置しているため51点のリソース画像と、下記のXMLと計52点のリソースファイルを使用してLIKEボタンのアニメーションを実現しています。

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android" android:oneshot="true">
    <item android:drawable="@drawable/like_animation_01" android:duration="30" />
    <item android:drawable="@drawable/like_animation_02" android:duration="30" />
    <item android:drawable="@drawable/like_animation_03" android:duration="30" />
    <item android:drawable="@drawable/like_animation_04" android:duration="30" />
    <item android:drawable="@drawable/like_animation_05" android:duration="30" />
    <item android:drawable="@drawable/like_animation_06" android:duration="30" />
    <item android:drawable="@drawable/like_animation_07" android:duration="30" />
    <item android:drawable="@drawable/like_animation_08" android:duration="30" />
    <item android:drawable="@drawable/like_animation_09" android:duration="30" />
    <item android:drawable="@drawable/like_animation_10" android:duration="30" />
    <item android:drawable="@drawable/like_animation_11" android:duration="30" />
    <item android:drawable="@drawable/like_animation_12" android:duration="30" />
    <item android:drawable="@drawable/like_animation_13" android:duration="30" />
    <item android:drawable="@drawable/like_animation_14" android:duration="30" />
    <item android:drawable="@drawable/like_animation_15" android:duration="30" />
    <item android:drawable="@drawable/like_animation_16" android:duration="30" />
    <item android:drawable="@drawable/like_animation_17" android:duration="30" />
</animation-list>

アニメーション自体は 『背景』『効果』『ハート』『外枠』 と4つのレイヤーに分かれたものになっています。
各レイヤーの振る舞いは以下のようになっています。

レイヤー 振る舞い
背景 時間の経過とともに白からピンクに色が変化
効果 背景が変化するタイミングで白の円として出現し時間の経過とともに
透過率とスケールを変えながら消えていく
このレイヤーのおかげで一瞬ボタンがキラっとするように見える
ハート 時間の経過とともにピンクから白に色を変化しながら2回転
外枠 時間の経過とともに透過率が変わり消えていく

次にこれらの情報をAndroid Icon Animatorに展開させていきます。

Android Icon Animatorでリソースファイルを作成する

事前に元になるSVGファイルを作成しておいてください。レイヤーごとにアニメーションが付けられるので必要に応じてレイヤーを分けておくと後の工程が楽になります。
Android Icon AnimatorをWebブラウザで開いて、SVGファイルをそこにドラッグアンドドロップすると、左下に各要素が pathlayer group として階層表示されます。

f:id:vasilyjp:20161026182042p:plain

takahiromさんの記事でもありますが、pathとlayer groupではできることが違っているため、必要に応じて階層を入れ替えたり、要素を追加したりして階層を整えます。
例えば、今回のLIKEボタンは以下のように階層を整えることができます。

レイヤー 配置方法
背景 色が変化するだけなのでpathをそのまま配置
効果 透過率とスケールを変化させるのでlayer groupの中にpathを配置
スケールを中心を基準に変化させるのでlayer groupのpivotを中心に設定
ハート 色とスケールを変化させるのでlayer groupの中にpathを配置
スケールを中心を基準に変化させるのでlayer groupのpivotを中心に設定
外枠 透過率が変化するだけなのでpathをそのまま配置

加えて、要素を管理しやすくするために各要素のidを整理してもいいと思います。
階層を入れ替えて、idを整理したものが以下になります。

f:id:vasilyjp:20161026182102p:plain

ここから各要素の時計アイコンをクリックしてアニメーションを作成していきます。大まかに配置を行ってから右上のフォームを使って調整を行うとスムーズにいきます。
実際に元のLIKEボタンに似せてアニメーションを設置した画面が以下になります。

f:id:vasilyjp:20161026182127p:plain

最後に画面の左側にある ExportAnimated vector drawable(s) を選択するとリソースファイルが出力されます。AnimatedVectorDrawableやAnimatedVectorDrawableCompatを使用して読み込むと、以下のようにアニメーションが再生されます。
ベクター画像のアニメーションのため、画面いっぱいに表示させても問題ない見た目になります。

f:id:vasilyjp:20161026182153g:plain

Android Icon Animatorを使う上で気をつけるポイント

こまめにSaveを行う

現状のAndroid Icon Animatorには自動保存機能などは存在しないため、こまめに画面の左側にある FileSave を選択して、ローカルに .iconanim ファイルをバックアップしておくことをオススメします。
このファイルを FileOpen で開くことでプロジェクトを復旧することができるので、Webブラウザが急に固まったときの惨事を軽減することができます。
私もアニメーションのチェックをしている際に過負荷で固まってしまったことがあり、Saveをしていなかったことでヒドく落ち込みました。

API Level 22以下をサポートしている場合はpathDataのアニメーションは使わない

手元で確認したところpathDataのアニメーションはAPI Level 22以下では動かないことがわかりました。
そのため、API Level 22以下をサポートしているアプリはpathDataを変更するアニメーションは使わない方が良さそうです。作りたいアニメーションが他の要素を使うことで実現可能であればそちらを使って対応するようにしましょう。

API Level 22以下で1つの要素に複数の異なるアニメーションを設定する場合には注意

API Level 22以下の場合、1つの要素に複数の異なるアニメーションを設定すると、2つ目以降のアニメーションが上手く動作しないことがわかりました。今回の場合だと 効果 の部分で行っている scaleXscaleY がそれに当たります。
この問題に遭遇した場合は作成したリソースファイルを直接触って target を分けることで解決できます。

修正前

<target android:name="effect_layout">
    <aapt:attr name="android:animation">
        <set xmlns:android="http://schemas.android.com/apk/res/android">
            <objectAnimator
                android:name="effect_layout"
                android:duration="330"
                android:interpolator="@android:anim/decelerate_interpolator"
                android:propertyName="scaleX"
                android:startOffset="60"
                android:valueFrom="1"
                android:valueTo="1.333"
                android:valueType="floatType" />
            <objectAnimator
                android:name="effect_layout"
                android:duration="330"
                android:interpolator="@android:anim/decelerate_interpolator"
                android:propertyName="scaleY"
                android:startOffset="60"
                android:valueFrom="1"
                android:valueTo="1.333"
                android:valueType="floatType" />
        </set>
    </aapt:attr>
</target>

修正後

<target android:name="effect_layout">
    <aapt:attr name="android:animation">
        <objectAnimator
            android:name="effect_layout"
            android:duration="330"
            android:interpolator="@android:anim/decelerate_interpolator"
            android:propertyName="scaleX"
            android:startOffset="60"
            android:valueFrom="1"
            android:valueTo="1.333"
            android:valueType="floatType" />
    </aapt:attr>
</target>
<target android:name="effect_layout">
    <aapt:attr name="android:animation">
        <objectAnimator
            android:name="effect_layout"
            android:duration="330"
            android:interpolator="@android:anim/decelerate_interpolator"
            android:propertyName="scaleY"
            android:startOffset="60"
            android:valueFrom="1"
            android:valueTo="1.333"
            android:valueType="floatType" />
    </aapt:attr>
</target>

また ハート のように同一のアニメーションを複数実行する場合には問題がないことを確認しています。
今後Android Icon AnimatorやSupport Libraryで改善されると思うので、それまではこの問題に注意してください。

最後に

今回紹介したAndroid Icon Animatorの使い方を覚える際には、Android Icon Animatorのページ上部からダウンロードできるサンプルファイルを活用してみてください。
サンプルファイルを一通り触れば基本的なことはできるようになると思います。

AnimatedVectorDrawableやAnimatedVectorDrawableCompatを使用することでプロジェクトからリソースファイルを多く減らすことができます。
今回作り直したLIKEボタンだけでも52点のファイルを削減することができたので、アニメーションのクオリティを落とさずにリソースファイルの軽量化を進める際にはかなり有効な手段だと思うのでぜひとも試してみてください。

最後の最後に、VASILYではiQONを一緒に開発してくれるAndroidエンジニアを募集しています。興味がある方は以下のリンクをご覧ください。