본 포스팅은 아래 포스팅들과 관련있습니다.
- [Android] Property Animation – Rotate (회전)
- [Android] Property Animation – Translate (이동)
- [Android] Property Animation – Scale (확대/축소)
- [Android] Property Animation – Fade (나타나기/사라지기)
- [Android] Property Animation – Color (색상 변경)
Android Property Animation 중 눈내리기 효과를 구현해보려고 했는데, 마침 오늘 첫 눈이 내렸습니다. 이번에 구현할 눈내리기 효과의 결과물은 아래와 같습니다.
이번 구현은 사실 이전의 애니메이션 효과와 크게 다르지 않습니다. 이전에 다뤘던 Translation 애니메이션의 응용 버전이랄까요? Codelab의 starShower를 조금 각색한 버전이니 Codelab을 참고하시면 큰 도움이 되실 겁니다.
먼저 크게 다음과 같은 3단계로 구현을 하게 됩니다.
- 하늘에서 내릴 눈 객체 생성
- 생성한 눈 객체를 떨어뜨리기
- 반복해서 여러 눈 객체를 떨어뜨리기
1. 하늘에서 내릴 눈 객체 생성
아래와 같이 별도 함수로 분리하여 눈 객체를 생성하였습니다.
private fun makeSnowObject() = AppCompatImageView(this).apply {
setImageResource(R.drawable.ic_snow)
scaleX = Math.random().toFloat() * 0.3f + .2f
scaleY = scaleX
measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
}
return type은 ImageView가 됩니다. scaleX에 랜덤 값을 적용하였는데, 이는 눈 객체의 크기를 랜덤하게 설정하는 것을 의미합니다. 최소 0.2배 ~ 최대 0.5배 크기로 결정됩니다.
2. 생성한 눈 객체를 떨어뜨리기
이번 스텝이 사실 애니메이션과 관련한 핵심적인 부분이라 할 수 있습니다. 우선 코드는 다음과 같습니다. 상세 설명은 주석을 참고하시기 바랍니다.
private fun snowing() {
// 눈 객체를 생성하여 container에 추가 (container는 해당 액티비티의 전체 layout입니다.)
val snowObj = makeSnowObject()
container.addView(snowObj)
// 눈 객체의 높이
val snowHeight = snowObj.measuredHeight * snowObj.scaleY
// 눈 객체가 하늘에서 내릴 때 랜덤한 위치에서 내리기 시작하여, 랜덤한 위치로 떨어지기 위해 시작/종료 지점의 X 좌표 계산
val startPoint = Random.nextFloat() * container.width
val endPoint = Random.nextFloat() * container.width
// 눈 객체의 시작 위치와 종료 위치의 X 좌표
val moverX = ObjectAnimator.ofFloat(snowObj, View.TRANSLATION_X, startPoint, endPoint)
// 눈 객체의 시작 위치와 종료 위치의 Y 좌표
// 화면의 최상단보다 좀더 위쪽에서 시작하도록 하기 위해 0이 아닌 -snowHeight로 지정
// 화면의 하단으로 사라지게끔 하기 위해 종료 위치를 container height + snowHeight로 지정
val moverY = ObjectAnimator.ofFloat(snowObj, View.TRANSLATION_Y, -snowHeight, (container.height + snowHeight))
// 눈이 떨어지는 속도 조절
moverY.interpolator = AccelerateInterpolator(1f)
// 2개의 애니메이션을 하나로 묶어서 처리하기 위해 AnimatorSet 사용
val set = AnimatorSet().apply {
playTogether(moverX, moverY)
duration = (Math.random() * 3000 + 3000).toLong()
addListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator?) {
// 애니메이션 종료 뒤 해당 눈 객체 제거
container.removeView(snowObj)
}
})
}
set.start()
}
눈이 떨어지는 속도를 조절하기 위해 interpolator에 AccelerateInterpolator를 사용하였습니다. 애니메이션이 시간 흐름에 따라 움직임의 속도?를 제어하기 위해 interpolator를 사용할 수 있는데, 이를 테면 설정한 시간 동안 균등하게 애니메이션 효과를 적용할 수도 있지만, 처음에는 빠르게 변하다 후반에는 천천히 변하게 하거나, 처음에는 천천히 변하다 후반에는 빠르게 변하게 할 수 있습니다. AccelerateInterpolator가 초반에는 천천히 시작하다 점점 빠르게 애니메이션을 보여주는 Interpolator입니다. 즉 중력 가속도를 표현하기 위해 본 예제에서는 사용한 케이스입니다. 자세한 내용은 공식 문서를 참고하시기 바랍니다.
3. 반복해서 여러 눈 객체를 떨어뜨리기
본 스텝은 애니메이션과는 크게 관련이 없습니다. 반복적으로 눈을 내리게 하기 위해 아래와 같이 Handler를 사용하였습니다. 상세 내용은 아래 코드에 주석으로 달았습니다.
private const val SNOWING_MESSAGE_ID = 10
// Handler.Callback을 구현합니다.
class SnowingActivity : AppCompatActivity(), Handler.Callback {
private var isSnowing: Boolean = true
private val delayedSnowing: Handler = Handler(this)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_snowing)
// 액티비티 시작 시 handler에 메세지를 보냅니다.
delayedSnowing.sendEmptyMessageDelayed(SNOWING_MESSAGE_ID, 100)
}
// ......
// 핸들러에서 메세지를 수신하는 부분을 오버라이드합니다.
override fun handleMessage(msg: Message): Boolean {
if (msg.what == SNOWING_MESSAGE_ID && isSnowing) {
// 눈 객체를 하나 생성하여 애니메이션 실행합니다.
snowing()
// 다음 눈 객체를 생성합니다.
delayedSnowing.sendEmptyMessageDelayed(SNOWING_MESSAGE_ID, 100)
}
return true
}
override fun onDestroy() {
super.onDestroy()
// 액티비티 라이프사이클 종료 시 더이상 눈 객체를 생성하지 않도록 플래그 값을 변경합니다.
isSnowing = false
// 동일하게 핸들러에 보내진 콜백이나 메세지들을 모두 제거합니다.
delayedSnowing.removeCallbacksAndMessages(null)
}
}
이것으로 코드랩에 나와있는 6가지의 Property Animation에 대해 모두 알아보았습니다. 제 포스팅에 사용한 코드는 아래 위치에서 확인하실 수 있습니다.
https://github.com/yoonhok524/Android-Sandbox/tree/master/Animation
'개발 > Android' 카테고리의 다른 글
[Android] Dagger – 1. @Inject (0) | 2020.11.08 |
---|---|
[Android] Dagger – intro (0) | 2020.11.08 |
[Android] Property Animation – Color (색상 변경) (0) | 2020.11.08 |
[Android] Property Animation – Fade (나타나기/사라지기) (0) | 2020.11.08 |
[Android] Property Animation – Scale (확대/축소) (0) | 2020.11.08 |