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

# Spring Animationとは
[SpringAnimation](https://developer.android.com/topic/libraries/support-library/preview/spring-animation.html)を使うと物理的な動きのアニメーションを実現することができます。
物理的な要素として、 `Dumping ratio`と `Stiffness`　を与えることができます。

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

```kotlin
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
バネの強度を定義します。この値が大きいほど伸縮時間が短くなります。

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

# Spring Animation例
では実際にSpringAnimationを使った例を示していきます。[github](https://github.com/TakuSemba/SpringSample/tree/master)にもコードを上げてます。

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

```kotlin


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](https://qiita-image-store.s3.amazonaws.com/0/93589/4b54b755-c1a9-50a1-956a-16dcdbe157cd.gif)


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

```kotlin

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](https://qiita-image-store.s3.amazonaws.com/0/93589/2cf7d64d-44ea-fe14-2133-5ac7b8af1922.gif)


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

```kotlin


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](https://qiita-image-store.s3.amazonaws.com/0/93589/365abb47-e133-78cc-4de3-3f77ed224edf.gif)


# 最後に
サンプルコードは[github](https://github.com/TakuSemba/SpringSample/tree/master)にあげてます。