[Android / Wear OS] 간단한 점수판 앱 제작하기 - ⑤ GestureDetector onDoubleTap, onFling 적용
점수 +, - 버튼을 구현했으니 세트 점수까지 구현해보자!
xml에 간단히 TextView와 Button을 적용한 화면은 다음과 같다.
세트 점수가 없을 때까지는 괜찮았는데, 굉장히 못생겨졌다...
버튼이 없으면 좀 나아질까 싶어 화면에 존재하는 모든 버튼을 제거해보았다.
전보다는 훨씬 봐줄만 한 것 같다. 그런데 버튼을 없애면 점수를 어떻게 올리고 내려야 할까?
고민을 하다가 화면을 한 번 탭하면 점수 증가, 두 번 탭하면 점수 감소로 기능을 구현하기로 결정하였다.
그리고 GestureDetector의 onDoubleTap() 을 사용하면 해당 기능을 사용할 수 있어 GestureDetector를 사용하여 기능을 구현해보았다.
@SuppressLint("ClickableViewAccessibility")
fun connectTextViewScore(context: Context, scoreboard: Scoreboard, textView: TextView){
val gestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
scoreboard.plusScore()
textView.text = scoreboard.score.toString()
return true
}
override fun onDoubleTap(e: MotionEvent): Boolean {
scoreboard.minusScore()
textView.text = scoreboard.score.toString()
return true
}
})
textView.setOnTouchListener { _, event ->
gestureDetector.onTouchEvent(event)
true
}
}
보는 것과 같이 기능이 잘 작동한다. 탭과 더블 탭에 이어서 위로 스와이프, 아래로 스와이프하여 점수를 올리거나 내리는 것도 좋은 방법일 것 같아 GestureDetector의 onFling()을 사용하여 기능을 구현해주었다.
@SuppressLint("ClickableViewAccessibility")
fun connectTextViewScore(context: Context, scoreboard: Scoreboard, textView: TextView){
val gestureDetector = GestureDetector(context, object : GestureDetector.SimpleOnGestureListener() {
override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
scoreboard.plusScore()
textView.text = scoreboard.score.toString()
return true
}
override fun onDoubleTap(e: MotionEvent): Boolean {
scoreboard.minusScore()
textView.text = scoreboard.score.toString()
return true
}
val SWIPE_THRESHOLD = 50
val SWIPE_VELOCITY_THRESHOLD = 50
override fun onFling(
e1: MotionEvent?,
e2: MotionEvent,
velocityX: Float,
velocityY: Float
): Boolean {
if (e1 != null){
val diffY = e2.y - e1.y
if (Math.abs(diffY) > SWIPE_THRESHOLD &&
Math.abs(velocityY) > SWIPE_VELOCITY_THRESHOLD){
if (diffY > 0){
scoreboard.minusScore()
textView.text = scoreboard.score.toString()
}
else{
scoreboard.plusScore()
textView.text = scoreboard.score.toString()
}
}
}
return true
}
})
textView.setOnTouchListener { _, event ->
gestureDetector.onTouchEvent(event)
true
}
}
공식 문서를 참고하면 e1은 처음으로 터치가 시작된 MotionEvent이며 e2는 Fling(스와이프)이 일어난 이후의 MotionEvent이다. 즉 e2의 좌표에서 e1의 좌표를 빼면 어디에서 어디로 스와이프하였는지 벡터를 알 수 있다.
단 주의해야 할 점이 있는데 스마트폰에서 y축의 증가 방향은 아래쪽이라는것이다.
실제로 오른쪽 아래로 스와이프하였을 때 로그를 찍어보면 x축, y축이 모두 증가하였음을 알 수 있다.
이에 유의하여 방향을 잘 설정하고 각각 함수를 구현하여주면 아래와 같이 잘 작동한다.
GestureDetector.OnGestureListener | Android Developers
developer.android.com