일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- ADB
- 안드로이드
- 유튜브
- 깃헙
- 의존성주입
- 코틀린
- coroutine
- Kotlin
- Github
- 레트로핏
- viewpager
- Retrofit
- 코루틴
- RecyclerView
- studio
- 안드로이드 스튜디오
- 안드로이드스튜디오
- 에러
- dart
- WebView
- 스튜디오
- 안스
- image
- build
- MVVM
- GIT
- Android
- Gradle
- error
- 웹뷰
- Today
- Total
코딩하는 일용직 노동자
AnimationUtils 를 버리고 ObjectAnimator를 이용해보자. 본문
# 들어가며
안드로이드의 애니메이션은 구현하기가 까다롭습니다.
특히 translate 애니메이션을 한 후 클릭이벤트를 확인해보면 엉뚱한 현상을 경험하게 됩니다.
translate 애니메이션으로 위치를 이동시키면 이동한 곳에서 클릭이벤트가 발생하는것이 아니라, 이동하기 전 위치에서 클릭이벤트가 발생합니다.
# 해결방법 1
AnimationUtils 클래스의 loadAnimation 함수를 이용해서 구현할 경우 이런현상을 경험하게 됩니다.
저의 경우 이 문제를 해결하기 위해 처음에는 똑같이 생긴 뷰를 애니메이션이 끝나는 위치에 숨겨놓았다가
애니메이션이 끝나면 원래의 뷰를 감추고 새로운 뷰를 노출하는 식으로 해결했습니다.
하지만 이 방법은 깔끔하지 못합니다.
불필요한 뷰를 하나 더 만들어야 하고, 이벤트를 받기위해 id도 부여해야 합니다.
또한 애니메이션 리스너를 이용해서 애니메이션이 끝났는지를 파악해야 합니다.
# 해결방법 2
ObjectAnimator 을 이용하면 이같은 현상을 쉽게 해결할 수 있습니다.
애니메이션이 끝나고 뷰의 위치가 바뀌어도 클릭이벤트는 현재 뷰의 위치에서 잘 발생합니다.
ObjectAnimator 의 자세한 정보는 이곳에서 확인하실 수 있습니다.
이번 포스팅에서는 translate 애니메이션을 이용해 보겠습니다.
import android.animation.ObjectAnimator
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.animation.AnimationUtils
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_anim.*
class AnimActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_anim)
initEvent()
}
private fun initEvent() {
llTopArea.setOnClickListener {
Toast.makeText(this@AnimActivity, "Top 클릭", Toast.LENGTH_SHORT).show()
}
btnStartAnim.setOnClickListener {
startAnimation()
// startObjectAnimation()
}
}
private fun startAnimation() {
var anim = AnimationUtils.loadAnimation(this, R.anim.translate_up).apply {
fillAfter = true
}
llTopArea.startAnimation(anim)
}
private fun startObjectAnimation() {
var height = llTopArea.height.toFloat()
var animBg = ObjectAnimator.ofFloat(llTopArea, "translationY", 0F, -height)
animBg.duration = 300
animBg.start()
}
}
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".anim.AnimActivity">
<LinearLayout
android:id="@+id/llTopArea"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_marginTop="100dp"
android:background="@color/colorAccent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Top"
android:textColor="#000000"
android:textSize="20dp" />
</LinearLayout>
<Button
android:id="@+id/btnStartAnim"
android:layout_width="match_parent"
android:layout_height="60dp"
android:text="이동"
android:textSize="20dp"
android:textColor="#000000"/>
</LinearLayout>
</layout>
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
android:interpolator="@android:anim/linear_interpolator"
android:fillAfter="true">
<translate
android:duration="500"
android:fromXDelta="0"
android:toXDelta="0"
android:fromYDelta="0"
android:toYDelta="-100%"/>
</set>
# 마치며
소스상에 AnimationUtils를 이용해 구현하는 것에 비해서 큰 차이없이 구현이 가능합니다.
애니메이션의 시작과 끝을 알기위해 AnimatorListenerAdapter를 이용할 수 있습니다.
그리고 여러 애니메이션을 동시에 동작하기 위해 AnimatorSet을 이용할 수도 있습니다.
무엇보다 클릭이벤트 때문에 똑같이 생긴 뷰를 두개 만드는 더러운(?) 방법을 이용하지 않아 좋습니다.
앞으로는 ObjectAnimator 와 ValueAnimator 를 이용해서 구현하시길 추천합니다.
'안드로이드' 카테고리의 다른 글
AsyncTask를 대체할 라이브러리 Needle (0) | 2020.07.30 |
---|---|
WebView 에서 로드된 html 소스 가져오기 (0) | 2020.07.20 |
Facebook Key Hash 생성/등록하기 (0) | 2020.07.01 |
안드로이드 이메일 보내기 소스 (0) | 2020.06.30 |
안드로이드 상단 Status Bar 컬러값 변경하기 (0) | 2020.06.25 |