LoginSignup
2
0

More than 5 years have passed since last update.

それっぽいローディングアニメーションをAnimatedVectorDrawableで作る

Posted at

onDrawで描画しようかなーと思っていたけど、AnimatedVectorDrawableでいけるんじゃないかと気づいたので、お試し。

出来あがり

dots_wave.gif

お悩みポイント

Shape Shifterに大量の丸をいい感じに追加したい

  • 取っ掛かりとしてShape Shifterを使ったのだけど、Sketchからエクスポートした丸を複数インポートする方法がよくわからなかった
  • 結果として、以下の手順を踏むことでうまくインポートできた
    1. Sketchでアートボードを作って、必要な数の丸を並べる
    2. アートボードをSVGとして、エクスポート
      • このSVGをShape Shifterにインポートしても、丸が個別に認識されなかった…
    3. エクスポートしたSVGをAndroidStudioに取り込んで、VectorDrawableに変換
    4. VectorDrawableをShape Shifterにインポート
    5. 丸が個別に認識されるので、いい感じにアニメーションを当てれる

どうやってループさせるの?

  • repeatModeみたいな設定することが出来なさげ
    • 個別のobjectAnimatorには設定できるかもしれないけど(未検証)、全体のアニメーションを一纏まりとしてループしてほしい
  • 実直にアニメーションの終了タイミングを捕まえて、再度startを実行した
こんな感じ
val imageView = findViewById<AppCompatImageView>(R.id.image_view)
val drawable = imageView.drawable as AnimatedVectorDrawableCompat
drawable.registerAnimationCallback(object : Animatable2Compat.AnimationCallback() {
    override fun onAnimationEnd(drawable: Drawable?) {
        imageView.post { (drawable as AnimatedVectorDrawableCompat).start() }
    }
})
drawable.start()

ちなみにXMLファイルはどうなったか

  • 長くなった
    • アニメーションの設定は全てをShape Shifter上で行った訳ではなくて、2個分設定してエクスポートしたものをコピペして量産した
    • そこでタイミングなども調整
    • こう見ると丸のpathにも当然規則性がある訳で、無理にShape Shifterに大量の丸をインポートしなくてもコピペでいけたなと…
avd_dots_anim.xml
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:aapt="http://schemas.android.com/aapt">
    <aapt:attr name="android:drawable">
        <vector
            android:name="dots"
            android:width="64dp"
            android:height="12dp"
            android:viewportHeight="12"
            android:viewportWidth="64">
            <group android:name="dot_1">
                <path
                    android:name="dot_path_1"
                    android:fillColor="#D8D8D8"
                    android:pathData="M 4 6 M 2 6 C 2 4.895 2.895 4 4 4 C 5.105 4 6 4.895 6 6 C 6 7.105 5.105 8 4 8 C 2.895 8 2 7.105 2 6"
                    android:strokeColor="#00000000"
                    android:strokeWidth="1" />
            </group>
            <group android:name="dot_2">
                <path
                    android:name="dot_path_2"
                    android:fillColor="#D8D8D8"
                    android:pathData="M 12 6 M 10 6 C 10 4.895 10.895 4 12 4 C 13.105 4 14 4.895 14 6 C 14 7.105 13.105 8 12 8 C 10.895 8 10 7.105 10 6"
                    android:strokeColor="#00000000"
                    android:strokeWidth="1" />
            </group>
            <group android:name="dot_3">
                <path
                    android:name="dot_path_3"
                    android:fillColor="#D8D8D8"
                    android:pathData="M 20 6 M 18 6 C 18 4.895 18.895 4 20 4 C 21.105 4 22 4.895 22 6 C 22 7.105 21.105 8 20 8 C 18.895 8 18 7.105 18 6"
                    android:strokeColor="#00000000"
                    android:strokeWidth="1" />
            </group>
            <group android:name="dot_4">
                <path
                    android:name="dot_path_4"
                    android:fillColor="#D8D8D8"
                    android:pathData="M 28 6 M 26 6 C 26 4.895 26.895 4 28 4 C 29.105 4 30 4.895 30 6 C 30 7.105 29.105 8 28 8 C 26.895 8 26 7.105 26 6"
                    android:strokeColor="#00000000"
                    android:strokeWidth="1" />
            </group>
            <group android:name="dot_5">
                <path
                    android:name="dot_path_5"
                    android:fillColor="#D8D8D8"
                    android:pathData="M 36 6 M 34 6 C 34 4.895 34.895 4 36 4 C 37.105 4 38 4.895 38 6 C 38 7.105 37.105 8 36 8 C 34.895 8 34 7.105 34 6"
                    android:strokeColor="#00000000"
                    android:strokeWidth="1" />
            </group>
            <group android:name="dot_6">
                <path
                    android:name="dot_path_6"
                    android:fillColor="#D8D8D8"
                    android:pathData="M 44 6 M 42 6 C 42 4.895 42.895 4 44 4 C 45.105 4 46 4.895 46 6 C 46 7.105 45.105 8 44 8 C 42.895 8 42 7.105 42 6"
                    android:strokeColor="#00000000"
                    android:strokeWidth="1" />
            </group>
            <group android:name="dot_7">
                <path
                    android:name="dot_path_7"
                    android:fillColor="#D8D8D8"
                    android:pathData="M 52 6 M 50 6 C 50 4.895 50.895 4 52 4 C 53.105 4 54 4.895 54 6 C 54 7.105 53.105 8 52 8 C 50.895 8 50 7.105 50 6"
                    android:strokeColor="#00000000"
                    android:strokeWidth="1" />
            </group>
            <group android:name="dot_8">
                <path
                    android:name="dot_path_8"
                    android:fillColor="#D8D8D8"
                    android:pathData="M 60 6 M 58 6 C 58 4.895 58.895 4 60 4 C 61.105 4 62 4.895 62 6 C 62 7.105 61.105 8 60 8 C 58.895 8 58 7.105 58 6"
                    android:strokeColor="#00000000"
                    android:strokeWidth="1" />
            </group>
        </vector>
    </aapt:attr>
    <target android:name="dot_1">
        <aapt:attr name="android:animation">
            <set>
                <objectAnimator
                    android:duration="250"
                    android:interpolator="@android:interpolator/fast_out_slow_in"
                    android:propertyName="translateY"
                    android:startOffset="100"
                    android:valueFrom="0"
                    android:valueTo="4"
                    android:valueType="floatType" />
                <objectAnimator
                    android:duration="500"
                    android:interpolator="@android:interpolator/fast_out_slow_in"
                    android:propertyName="translateY"
                    android:startOffset="350"
                    android:valueFrom="4"
                    android:valueTo="-4"
                    android:valueType="floatType" />
                <objectAnimator
                    android:duration="250"
                    android:interpolator="@android:interpolator/fast_out_slow_in"
                    android:propertyName="translateY"
                    android:startOffset="850"
                    android:valueFrom="-4"
                    android:valueTo="0"
                    android:valueType="floatType" />
            </set>
        </aapt:attr>
    </target>
    <target android:name="dot_2">
        <aapt:attr name="android:animation">
            <set>
                <objectAnimator
                    android:duration="250"
                    android:interpolator="@android:interpolator/fast_out_slow_in"
                    android:propertyName="translateY"
                    android:startOffset="200"
                    android:valueFrom="0"
                    android:valueTo="4"
                    android:valueType="floatType" />
                <objectAnimator
                    android:duration="500"
                    android:interpolator="@android:interpolator/fast_out_slow_in"
                    android:propertyName="translateY"
                    android:startOffset="450"
                    android:valueFrom="4"
                    android:valueTo="-4"
                    android:valueType="floatType" />
                <objectAnimator
                    android:duration="250"
                    android:interpolator="@android:interpolator/fast_out_slow_in"
                    android:propertyName="translateY"
                    android:startOffset="950"
                    android:valueFrom="-4"
                    android:valueTo="0"
                    android:valueType="floatType" />
            </set>
        </aapt:attr>
    </target>
    <target android:name="dot_3">
        <aapt:attr name="android:animation">
            <set>
                <objectAnimator
                    android:duration="250"
                    android:interpolator="@android:interpolator/fast_out_slow_in"
                    android:propertyName="translateY"
                    android:startOffset="300"
                    android:valueFrom="0"
                    android:valueTo="4"
                    android:valueType="floatType" />
                <objectAnimator
                    android:duration="500"
                    android:interpolator="@android:interpolator/fast_out_slow_in"
                    android:propertyName="translateY"
                    android:startOffset="550"
                    android:valueFrom="4"
                    android:valueTo="-4"
                    android:valueType="floatType" />
                <objectAnimator
                    android:duration="250"
                    android:interpolator="@android:interpolator/fast_out_slow_in"
                    android:propertyName="translateY"
                    android:startOffset="1050"
                    android:valueFrom="-4"
                    android:valueTo="0"
                    android:valueType="floatType" />
            </set>
        </aapt:attr>
    </target>
    <target android:name="dot_4">
        <aapt:attr name="android:animation">
            <set>
                <objectAnimator
                    android:duration="250"
                    android:interpolator="@android:interpolator/fast_out_slow_in"
                    android:propertyName="translateY"
                    android:startOffset="400"
                    android:valueFrom="0"
                    android:valueTo="4"
                    android:valueType="floatType" />
                <objectAnimator
                    android:duration="500"
                    android:interpolator="@android:interpolator/fast_out_slow_in"
                    android:propertyName="translateY"
                    android:startOffset="650"
                    android:valueFrom="4"
                    android:valueTo="-4"
                    android:valueType="floatType" />
                <objectAnimator
                    android:duration="250"
                    android:interpolator="@android:interpolator/fast_out_slow_in"
                    android:propertyName="translateY"
                    android:startOffset="1150"
                    android:valueFrom="-4"
                    android:valueTo="0"
                    android:valueType="floatType" />
            </set>
        </aapt:attr>
    </target>
    <target android:name="dot_5">
        <aapt:attr name="android:animation">
            <set>
                <objectAnimator
                    android:duration="250"
                    android:interpolator="@android:interpolator/fast_out_slow_in"
                    android:propertyName="translateY"
                    android:startOffset="500"
                    android:valueFrom="0"
                    android:valueTo="4"
                    android:valueType="floatType" />
                <objectAnimator
                    android:duration="500"
                    android:interpolator="@android:interpolator/fast_out_slow_in"
                    android:propertyName="translateY"
                    android:startOffset="750"
                    android:valueFrom="4"
                    android:valueTo="-4"
                    android:valueType="floatType" />
                <objectAnimator
                    android:duration="250"
                    android:interpolator="@android:interpolator/fast_out_slow_in"
                    android:propertyName="translateY"
                    android:startOffset="1250"
                    android:valueFrom="-4"
                    android:valueTo="0"
                    android:valueType="floatType" />
            </set>
        </aapt:attr>
    </target>
    <target android:name="dot_6">
        <aapt:attr name="android:animation">
            <set>
                <objectAnimator
                    android:duration="250"
                    android:interpolator="@android:interpolator/fast_out_slow_in"
                    android:propertyName="translateY"
                    android:startOffset="600"
                    android:valueFrom="0"
                    android:valueTo="4"
                    android:valueType="floatType" />
                <objectAnimator
                    android:duration="500"
                    android:interpolator="@android:interpolator/fast_out_slow_in"
                    android:propertyName="translateY"
                    android:startOffset="850"
                    android:valueFrom="4"
                    android:valueTo="-4"
                    android:valueType="floatType" />
                <objectAnimator
                    android:duration="250"
                    android:interpolator="@android:interpolator/fast_out_slow_in"
                    android:propertyName="translateY"
                    android:startOffset="1350"
                    android:valueFrom="-4"
                    android:valueTo="0"
                    android:valueType="floatType" />
            </set>
        </aapt:attr>
    </target>
    <target android:name="dot_7">
        <aapt:attr name="android:animation">
            <set>
                <objectAnimator
                    android:duration="250"
                    android:interpolator="@android:interpolator/fast_out_slow_in"
                    android:propertyName="translateY"
                    android:startOffset="700"
                    android:valueFrom="0"
                    android:valueTo="4"
                    android:valueType="floatType" />
                <objectAnimator
                    android:duration="500"
                    android:interpolator="@android:interpolator/fast_out_slow_in"
                    android:propertyName="translateY"
                    android:startOffset="950"
                    android:valueFrom="4"
                    android:valueTo="-4"
                    android:valueType="floatType" />
                <objectAnimator
                    android:duration="250"
                    android:interpolator="@android:interpolator/fast_out_slow_in"
                    android:propertyName="translateY"
                    android:startOffset="1450"
                    android:valueFrom="-4"
                    android:valueTo="0"
                    android:valueType="floatType" />
            </set>
        </aapt:attr>
    </target>
    <target android:name="dot_8">
        <aapt:attr name="android:animation">
            <set>
                <objectAnimator
                    android:duration="250"
                    android:interpolator="@android:interpolator/fast_out_slow_in"
                    android:propertyName="translateY"
                    android:startOffset="800"
                    android:valueFrom="0"
                    android:valueTo="4"
                    android:valueType="floatType" />
                <objectAnimator
                    android:duration="500"
                    android:interpolator="@android:interpolator/fast_out_slow_in"
                    android:propertyName="translateY"
                    android:startOffset="1050"
                    android:valueFrom="4"
                    android:valueTo="-4"
                    android:valueType="floatType" />
                <objectAnimator
                    android:duration="250"
                    android:interpolator="@android:interpolator/fast_out_slow_in"
                    android:propertyName="translateY"
                    android:startOffset="1550"
                    android:valueFrom="-4"
                    android:valueTo="0"
                    android:valueType="floatType" />
            </set>
        </aapt:attr>
    </target>
</animated-vector>
2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0