Animated Vector Drawableで押下時にアイコンの形が変わるアニメーションを作ってみました

公開日: 2021年02月24日最終更新日: 2021年10月17日

ボタンを押すとアイコンがアニメーションして切り替わる、アレを作りたいと思います。 今回作成したサンプルアプリのコードはGitHubにあります

Animated Vector Drawableについて学ぶに当たり、以下を参考にしました。
https://github.com/DroidGirls/Meetup/tree/master/3_vector_drawable

モーフアニメーションのためにvector drawableのpathDataを理解しておく必要があります。
VectorDrawableのpathDataを理解してアイコンからアイコンへのモーフアニメーションを自在に扱えるようになる、に書いていますので、そちらもご確認ください。

AniumatedVectorDrawableについて

vector画像のpathDataを変更したり、回転、モーフすることでアプリアイコンの切り替えアニメーションを実現します。
AniumatedVectorDrawableを使用する、にサンプルがあります。 一番下の動画を見ると、三角の図形が円運動しながら四角形に変わっていくアニメーションであることがわかります。

このアニメーションを実現するために、xmlファイルで以下の3つの要素を使用しています。

  • <vector>要素を持つVectorDrawable
  • <objectAnimator>要素によるrotationやmorph(pathの変形)などのアニメーション定義
  • <animated-vector>要素で、上記のvector drawableとアニメーション定義を参照してまとめるAnimatedVectorDrawable

それぞれ独立したファイルで定義することもできますが、複雑な XML リソースをインライン化する に記載されている通り、インライン化することができます。

上記のページには次のように記載されています。

『<aapt:attr > XML タグは、このタグの子をリソースとして扱い、それぞれ独自のリソース ファイルに抽出するよう、AAPT に伝えます。属性名の値は、親タグ内でインライン リソースを使用する場所を指定します。 AAPT が、すべてのインライン リソースを対象としてリソース ファイルとリソース名を生成します。このインライン形式を使用して作成されたアプリは、すべての Android バージョンと互換性を持ちます。』

<aapt:attr>を使うことで、インラインで記載したタグの内容をリソースファイルとしてAAPTが抽出してくれます。 インライン化することで、1箇所でしか使わないリソースをわざわざファイル化して管理する手間を減らすことができます。 共有して利用される内容であればファイル化して参照するのが良いでしょう。

今回は興味本位でインライン記載したXMLを試してみます。

サンプル

ここで見るAnimatedVectorDrawableのファイルはtriangle_to_rect.xmlになります。

以下の部分は静止状態のvector画像を定義しています。

<aapt:attr name="android:drawable">
    <vector
        android:width="64dp"
        android:height="64dp"
        android:viewportWidth="600"
        android:viewportHeight="600">
        <group
            android:name="rotationGroup"
            android:pivotX="300.0"
            android:pivotY="300.0"
            android:rotation="45.0">
            <path
                android:name="v"
                android:fillColor="#000000"
                android:pathData="M300,70 l 0,-70 70,70 0,0 -70,70z" />
        </group>
    </vector>
</aapt:attr>

描画されるサイズを64dp x 64dp で指定し、vector画像を描くキャンバスのサイズを600px x 600pxで指定しています。
<group>タグではキャンバスの中央(300, 300)を中心にrotationを指定して45度回転を加えています。
<path>タグで黒で塗りつぶした三角形のpath情報を指定しています。
pathDataについてはVectorDrawableのpathDataを理解してアイコンからアイコンへのモーフアニメーションを自在に扱えるようになるに記載しています。

次に回転のアニメーション指定です。 targetに上で出てきたrotationGroupを指定して、6000msかけて45度から405度まで一周させるアニメーションを定義しています。

<target android:name="rotationGroup">
    <aapt:attr name="android:animation">
        <objectAnimator
            android:duration="6000"
            android:propertyName="rotation"
            android:valueFrom="45"
            android:valueTo="405" />
    </aapt:attr>
</target>

最後にpathDataを変更するアニメーションです。pathDataを変更する、つまりアイコンの形を変えるモーフアニメーションを定義しています。
3000msかけてpathDataを"M300,70 l 0,-70 70,70 0,0 -70,70z"(三角形)から"M300,70 l 0,-70 70,0 0,140 -70,0 z"(四角形)に変更します。

<target android:name="v">
    <aapt:attr name="android:animation">
        <set>
            <objectAnimator
                android:duration="3000"
                android:propertyName="pathData"
                android:valueFrom="M300,70 l 0,-70 70,70 0,0 -70,70z"
                android:valueTo="M300,70 l 0,-70 70,0  0,140 -70,0 z"
                android:valueType="pathType" />
        </set>
    </aapt:attr>
</target>

これと逆の動きをするAnimatedVectorDrawableがrect_to_triangle.xmlです。

再生停止ボタンの例が pause_to_play.xmlplay_to_pause.xml です。

pathDataを試してみる

アニメーションする前後のpathはコマンドを合わせておく必要があります。 今回はコマンドを色々試す目的で2パターン作って試してみました。 M/m, L/l, v, h, zの文字で指定されたコマンドの数と順番が対応しています。

ファイルはpaths.xmlです。

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="path_play">
        M38,24
        L38,24
        L16,24
        L16,10
        z
        M38,24
        L38,24
        L16,38
        L16,24
        z
    </string>

    <string name="path_pause">
        M12,10
        L20,10
        L20,38
        L12,38
        z
        M28,10
        L36,10
        L36,38
        L28,38
        z
    </string>

    <string name="path_play2">
        M8,5
        v14
        h0
        l11,-7
        l0,0
        v0
        z
        M8,5
        v14
        h0
        l11,-7
        h0
        z
    </string>

    <string name="path_pause2">
        M6,19
        v0
        h4
        l0,-14
        l-4,0
        v14
        z
        M14,5
        v14
        h4
        l0,-14
        h-4
        z
    </string>

</resources>

所感

Vector画像のpathDataからは画像がすぐにはイメージできませんが、理解すると単純です。 わかりにくいものはツールを使って見やすくすればOKです。 適切にアニメーションを使えるとユーザーに分かりやすいUIが作れますので、今回調べてよかったと思います。