LoginSignup
6

More than 5 years have passed since last update.

新しく公開された Spring Animation を使う

Last updated at Posted at 2017-06-24

Spring Animationとは

SpringAnimationを使うと物理的な動きのアニメーションを実現することができます。
物理的な要素として、 Dumping ratioStiffness を与えることができます。

Damping ratio

物体の弾みの程度を定義します。この値が大きいほどバネのようによく弾みます。

DAMPING_RATIO_HIGH_BOUNCY //(0.2)
DAMPING_RATIO_MEDIUM_BOUNCY //(0.5)
DAMPING_RATIO_LOW_BOUNCY  //(0.75)
DAMPING_RATIO_NO_BOUNCY //(1.0)

Stiffness

バネの強度を定義します。この値が大きいほど伸縮時間が短くなります。

STIFFNESS_HIGH //(10000.0)
STIFFNESS_MEDIUM //(1500.0)
STIFFNESS_LOW //(200.0)
STIFFNESS_VERY_LOW //(50)

Spring Animation例

では実際にSpringAnimationを使った例を示していきます。githubにもコードを上げてます。

Spring Position

SpringAnimation.X SpringAnimation.Y を使うことでX軸、Y軸に対してSpringAnimationをかける事ができます。



class SpringPositionView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : View(context, attrs, defStyleAttr) {

    private companion object Params {
        private const val STIFFNESS = SpringForce.STIFFNESS_MEDIUM
        private const val DAMPING_RATIO = SpringForce.DAMPING_RATIO_HIGH_BOUNCY
    }

    private lateinit var xAnim: SpringAnimation
    private lateinit var yAnim: SpringAnimation

    init {

        viewTreeObserver.addOnGlobalLayoutListener {
            xAnim = SpringAnimation(this, SpringAnimation.X).apply {
                spring = SpringForce(x).apply {
                    stiffness = STIFFNESS
                    dampingRatio = DAMPING_RATIO
                }
            }
            yAnim = SpringAnimation(this, SpringAnimation.Y).apply {
                spring = SpringForce(y).apply {
                    stiffness = STIFFNESS
                    dampingRatio = DAMPING_RATIO
                }
            }
        }

        var dX = 0f
        var dY = 0f
        setOnTouchListener { view, event ->
            when (event.actionMasked) {
                MotionEvent.ACTION_DOWN -> {
                    dX = view.x - event.rawX
                    dY = view.y - event.rawY

                    xAnim.cancel()
                    yAnim.cancel()
                }
                MotionEvent.ACTION_MOVE -> {
                    animate()
                            .x(event.rawX + dX)
                            .y(event.rawY + dY)
                            .setDuration(0)
                            .start()
                }
                MotionEvent.ACTION_UP -> {
                    xAnim.start()
                    yAnim.start()
                }
            }
            true
        }
    }

}

giphy (2).gif

Spring Rotation

SpringAnimation.ROTATION を使うことで回転に対してSpringAnimationをかける事ができます。


class SpringRotationView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : View(context, attrs, defStyleAttr) {

    private companion object Params {
        val INITIAL_ROTATION = 0f
        val STIFFNESS = SpringForce.STIFFNESS_MEDIUM
        val DAMPING_RATIO = SpringForce.DAMPING_RATIO_HIGH_BOUNCY
    }

    private val rotationAnim: SpringAnimation = SpringAnimation(this, SpringAnimation.ROTATION).apply {
        spring = SpringForce(INITIAL_ROTATION).apply {
            stiffness = STIFFNESS
            dampingRatio = DAMPING_RATIO
        }
    }

    init {
        var currentRotation = 0f
        setOnTouchListener { view, event ->

            when (event.actionMasked) {
                MotionEvent.ACTION_DOWN -> {
                    rotationAnim.cancel()

                    currentRotation = rotationAmount(event.x, event.y)
                }
                MotionEvent.ACTION_MOVE -> {
                    val previousRotation = currentRotation

                    currentRotation = rotationAmount(event.x, event.y)
                    view.rotation += currentRotation - previousRotation
                }
                MotionEvent.ACTION_UP -> rotationAnim.start()
            }
            true
        }
    }

}

giphy (1).gif

Spring Scale

SpringAnimation.SCROLL_X SpringAnimation.SCROLL_Y を使うことで拡大縮小に対してSpringAnimationをかける事ができます。



class SpringScaleView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : View(context, attrs, defStyleAttr) {

    private companion object Params {
        val INITIAL_SCALE = 1f
        val STIFFNESS = SpringForce.STIFFNESS_MEDIUM
        val DAMPING_RATIO = SpringForce.DAMPING_RATIO_HIGH_BOUNCY
    }

    private val xAnim: SpringAnimation = SpringAnimation(this, SpringAnimation.SCALE_X).apply {
        spring = SpringForce(INITIAL_SCALE).apply {
            stiffness = STIFFNESS
            dampingRatio = DAMPING_RATIO
        }
    }

    private val yAnim: SpringAnimation = SpringAnimation(this, SpringAnimation.SCROLL_Y).apply {
        spring = SpringForce(INITIAL_SCALE).apply {
            stiffness = STIFFNESS
            dampingRatio = DAMPING_RATIO
        }
    }

    private val detector = ScaleGestureDetector(context,
            object:ScaleGestureDetector.SimpleOnScaleGestureListener() {
                override fun onScale(detector: ScaleGestureDetector): Boolean {
                    var scaleFactor = 1f
                    scaleFactor *= detector.scaleFactor
                    scaleX *= scaleFactor
                    scaleY *= scaleFactor
                    return true
                }
            })

    init {
        setOnTouchListener { _, event ->
            if (event.action == MotionEvent.ACTION_UP) {
                xAnim.start()
                yAnim.start()
            } else {
                xAnim.cancel()
                yAnim.cancel()
                detector.onTouchEvent(event)
            }
            true
        }
    }

}

giphy.gif

最後に

サンプルコードはgithubにあげてます。

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
6