안드로이드

[Android / Wear OS] 간단한 점수판 앱 제작하기 - ⑤ GestureDetector onDoubleTap, onFling 적용

kevinmj12 2024. 7. 6. 19:41

점수 +, - 버튼을 구현했으니 세트 점수까지 구현해보자!

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축이 모두 증가하였음을 알 수 있다.

이에 유의하여 방향을 잘 설정하고 각각 함수를 구현하여주면 아래와 같이 잘 작동한다.

 

 

 

https://developer.android.com/reference/android/view/GestureDetector.OnGestureListener#onFling(android.view.MotionEvent,%20android.view.MotionEvent,%20float,%20float)

 

GestureDetector.OnGestureListener  |  Android Developers

 

developer.android.com