이전 포스팅에서 언급했다싶이
스프링 애니메이션은 스프링력이라는 특정 값과 속도에 따라서 계산되는 애니메이션입니다.
물리학 효과가 들어간 스프링 애니메이션에서 가장 중요한 부분인 강성과 감쇠비에 대해서 얘기해보고자 합니다.
이전 포스팅을 못 보신 분들이라면 보고 오시는 것을 추천드립니다.
스프링 애니메이션을 적용할 때 사용자는 강성과 감쇠비를 적용할 수 있습니다.
사용자는 이 두 개의 속성을 임의로 조정하여 자신이 원하는 스프링 애니메이션을 만들 수 있게 됩니다.
'강성'은 스프링의 강도를 나타냅니다.
스프링이 느슨하면 우리는 적은 힘으로도 스프링을 굉장히 크게 늘릴 수 있고, 반대로 스프링이 빡빡하다면 굉장히 많은 힘을 줘도 얼마 벌리지 못합니다.
시스템에서 Default로 설정할 수 있는 강성 상수는 총 4가지 입니다.
STIFFNESS_HIGH
STIFFNESS_MEDIUM
STIFFNESS_LOW
STIFFNESS_VERY_LOW
아무런 값도 넣어주지 않는다면 STIFFNESS_MEDIUM으로 설정되어있습니다.
'감쇠비'는 스프링의 탄성을 나타냅니다.
쉽게 말해서 스프링을 땡겼다가 놓았을 때 스프링의 통통 튀는 정도에 영향을 미친다고 볼 수 있습니다.
강성과 마찬가지로 시스템에서 Default로 설정할 수 있는 감쇠비 상수는 총 4가지 입니다.
DAMPING_RATIO_HIGH_BOUNCY
DAMPING_RATIO_MEDIUM_BOUNCY
DAMPING_RATIO_LOW_BOUNCY
DAMPING_RATIO_NO_BOUNCY
아무런 값도 넣어주지 않는다면 DAMPING_RATIO_MEDIUM_BOUNCY으로 설정되어있습니다.
스프링 애니메이션은 SpringAnimation 클래스를 사용하여 원하는 뷰 객체에 애니메이션을 적용시킬 수 있습니다.
View.let { view ->
SpringAnimation(view, DynamicAnimation.TRANSLATION_Y, 0f).apply {
// set Stiffness and DampingRatio
stifness = SpringForce.STIFFNESS_LOW
dampingRatio = SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY
}
}
적용한 애니메이션을 시작하는 방법은 start() 또는 animateToFinalPosition()을 호출하는 두 가지 방법이 있습니다.
여기서 animateToFinalPosition()에 대해서 조금 더 알아보자면
animateToFinalPosition을 사용하여 여러개의 스프링 애니메이션을 연쇄적으로 사용 가능합니다.
미안하다... 이거 보여주려고 어그로 끌었다.. 스프링 애니메이션 수준 ㄹㅇ실화냐?
지난번 포스팅에서 보여주었던 연쇄 스프링 애니메이션 샘플을 가져와보도록 하겠습니다.

편의상 드래그 가능한 가장 위쪽 원을 1번, 중간의 원을 2번, 가장 아래쪽에 있는 원을 3번이라고 칭하겠습니다.
1번 원을 드래그 했을 때 변화하는 위치값을 받아 2번 원에 설정되어 있는 SpringAnimation 클래스에 위치를 전달하고, OnAnimationUpdateListener를 추가해 3번 원에게 연쇄적으로 좌표값을 보내줍니다.
// 2번의 X축이동 속성이 변경됨에 따라 3번 X축이동 SpringAnimation 객체로 전달
animX.addUpdateListener { _, value, _ ->
anim2x.animateToFinalPosition(value)
}
// 2번의 Y축이동 속성이 변경됨에 따라 3번 Y축이동 SpringAnimation 객체로 전달
animY.addUpdateListener { _, value, _ ->
anim2y.animateToFinalPosition(
value +
secondLayoutParams.topMargin +
binding.imgBallSky700.height
)
}
// 1번 원을 드래그하면 변화하는 좌표값을 2번 원의 SpringAnimation 객체로 전달
binding.imgBallSky200.setOnTouchListener { v, event ->
when (event.actionMasked) {
MotionEvent.ACTION_DOWN -> {
xDown = binding.imgBallSky200.x - event.rawX
yDown = binding.imgBallSky200.y - event.rawY
}
MotionEvent.ACTION_MOVE -> {
val newX = event.rawX + xDown
val newY = event.rawY + yDown
binding.imgBallSky200.animate()
.x(newX)
.y(newY)
.setDuration(0)
.start()
animX.animateToFinalPosition(newX)
animY.animateToFinalPosition(newY + firstLayoutParams.topMargin + binding.imgBallSky500.height)
}
MotionEvent.ACTION_UP -> {}
}
true
}
앱 서비스를 만들 때 애니메이션 효과는 무척이나 중요합니다. 사용자의 시각을 사로잡는데 가장 큰 요소라고 생각하기 때문이죠 ㅎㅎ
SpringAnimation이외에도 MotionLayout, VectorDrawableAnimation 등을 충분히 잘 활용하면
안드로이드에서도 보다 역동적인 애니메이션들을 구현할 수 있습니다. ( 물론 기본적인 앱 서비스의 로직이 정상적으로 돌아가는게 우선이지만요 ㅎㅎ )