[Android] Viewを左右にバイブレーションするアニメーションを作ってみた

プロパティアニメーションを使ってViewを左右に揺らしてみました。
2021.03.29

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

ユーザーが操作を間違えた時にViewを左右に揺らすアニメーションを実装する必要があったのでやってみました。今回はプロパティアニメーションを使って実現します。

開発環境

  • OS: MacOS Catalina
  • Android Studio: 4.1.3
  • Language: Kotlin 1.4.30

プロパティアニメーションの概要

プロパティアニメーションとは、オブジェクトのプロイパティを変化させることによってオブジェクトを移動したり色を変える仕組みです。ObjectAnimatorクラスのofFloat()でターゲットとなるオブジェクトとプロパティ、継続時間などを設定します。例えば横方向にオブジェクトをアニメーションさせる場合には、ofFloat()の引数に「対象となるview」、操作したいプロパティに「translationX」、開始値と終了値を指定します。setDuration()でアニメーションの継続時間をミリ秒で設定して、start()でアニメーションを開始します。translationXはfloatを必要とするプロパティなので、ObjectAnimator.ofFloatでインスタンスを生成します。

val target: View = findViewById(R.id.helloText) // 対象となるオブジェクト
ObjectAnimator.ofFloat(target, "translationX", 0f, 100f).apply {
    duration = 1000 // ミリ秒
    start() // アニメーション開始
}

連続でアニメーションを再生する

連続でアニメーションを再生したい場合は、AnimatorSetのplaySequentially()を使えば複数のObjectAnimatorを順番に実行できます。

        val animatorList: MutableList<Animator> = ArrayList()
        animatorList.add(ObjectAnimator.ofFloat(target, "translationX", 0f, 100f).setDuration(500))
        animatorList.add(ObjectAnimator.ofFloat(target, "translationY", 0f, 100f).setDuration(500))

        val set = AnimatorSet()
        set.playSequentially(animatorList)
        set.start()

振れ幅を徐々に小さくしていくアニメーション

最初の移動距離が最大で徐々に振れ幅を小さくするためには、ofFloat()の開始位置(第3引数)と終了位置(第4引数)を調整してオブジェクトの位置が繋がるように注意しながら値を小さくしていきます。移動スピードを徐々に小さくするためには、setDuration()の引数を最小値から開始し、最後に最大値を設定します。

全コード

// MainActivity.kt
import android.animation.Animator
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity

class MainActivity : AppCompatActivity() {

    /**
     * バイブレーションのアニメーション
     *
     * @param target 対象となるView
     */
    private fun vibrate(target: View) {

        val animatorList: MutableList<Animator> = ArrayList()

        // 移動距離(translationX)は、開始位置から左右に移動距離を100, 70, 50, 40...と徐々に減らしていく
        // 前のアニメーションと繋がるように終了位置(第4引数)の値を開始位置(第3引数)として設定する

        // 時間(duration)は10, 30, 60, 100...と徐々に増やしていく
        animatorList.add(ObjectAnimator.ofFloat(target, "translationX", 0f, -100f).setDuration(10)) 
        animatorList.add(ObjectAnimator.ofFloat(target, "translationX", -100f, 70f).setDuration(30))
        animatorList.add(ObjectAnimator.ofFloat(target, "translationX", 70f, -50f).setDuration(60))
        animatorList.add(ObjectAnimator.ofFloat(target, "translationX", -50f, 40f).setDuration(100))
        animatorList.add(ObjectAnimator.ofFloat(target, "translationX", 40f, -30f).setDuration(150))
        animatorList.add(ObjectAnimator.ofFloat(target, "translationX", -30f, 0f).setDuration(210))

        val set = AnimatorSet()
        set.playSequentially(animatorList) // 順番にアニメーションを実施
        set.start()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        findViewById<View>(R.id.button).setOnClickListener {
            val v: View = findViewById(R.id.helloText)
            vibrate(v)
        }
    }



}

まとめ

今回はコードだけでアニメーションさせてみました。プロパティアニメーションには様々なプロパティや仕組みがあります。詳細が知りたい方はリンク先を参考にしてみてください。

参考