깡샘 코틀린

08-1 터치와 키 이벤트

농농씨 2023. 6. 22. 17:39

터치 이벤트

앱의 화면에서 발생하는 사용자 이벤트는 터치(touch)이다. 터치란 손가락으로 화면을 잠시 눌렀다가 떼는 행위를 말한다. 앱은 사용자의 터치를 인식하고 화면을 손가락으로 눌렀는지, 떼었는지, 스와이프(swipe, 화면에 손가락을 댄 상태로 쓸어넘기는 동작)했는지 따라 알맞게 동작하도록 구현한다.

이처럼 앱의 화면에서 발생하는 사용자의 터치 이벤트를 처리하고 싶다면 액티비티 클래스에 터치 이벤트의 콜백 함수인 onTouchEvent()를 선언하면 된다.

✅콜백함수란? 어떤 이벤트가 발생하거나 시점에 도달했을 때 자동으로 호출하는 함수.

// 터치 이벤트 처리
class MainActivity : AppCompatActivity() { // 액티비티 클래스에
	(...생략...)
    override fun onToucnEvent(event: MotionEvent?): Boolean { // 터치이벤트의 콜백함수를 선언함
    	return super.onTouchEvent(event)
    }
}

액티비티에 onTouchEvent() 함수를 재정의(override)해서 선언만 해놓으면 사용자가 이 액티비티 화면을 터치하는 순간 onTouchEvent() 함수가 자동으로 호출된다. onTouchEvent()함수에 전달되는 매개변수는 MotionEvent 객체이며, 이 객체에 터치의 종류발생 지점(좌푯값)이 담긴다.

 

터치 이벤트의 종류

터치 이벤트는 다음 3가지로 구분된다.

  • ACTION_DOWN: 화면을 손가락으로 누른 순간의 이벤트
  • ACTION_UP: 화면에서 손가락을 떼는 순간의 이벤트
  • ACTION_MOVE: 화면을 손가락으로 누른 채로 이동하는 순간의 이벤트

만약 화면을 손가락으로 살짝 눌렀다가 떼었다면 onTouchEvent() 함수는 2번 호출된다.

첫번째는 ACTION_DOWN, 그 다음은 ACTION_UP 이벤트가 호출된다.

만약 화면을 터치해서 손가락을 이동한 후 떼었다면

처음에 ACTION_DOWN, 이동하면서 ACTION_MOVE 이벤트가 계속 발생하다가 손가락을 떼는 순간 ACTION_UP 이벤트가 발생한다.

// 터치 이벤트 처리
override fun onTouchEvent(event: MotionEvent?): Boolean { // 액티비티에서 콜백함수 재정의 선언
	when (event?.action) {
    	MotionEvent.ACTION_DOWN -> { // 화면 누르면 실행
        	Log.d("kkang", "Touch down event")
        }
        MotionEvent.ACTION_UP -> { // 화면 떼면 실행
        	Log.d("kkang", "Touch up event")
        }
    }
    return super.onTouchEvent(event) // super가 뭐였더라~~~
}

 

터치 이벤트 발생 좌표 얻기

터치 이벤트를 처리할 때는 이벤트 종류뿐만 아니라 이벤트가 발생한 지점을 알아야 하는 경우도 있다. 이 좌표도 onTouchEvent()함수의 매개변수의 MotionEvent 객체로 얻는다.

  • x: 이벤트가 발생한 뷰의 X좌표
  • y: 이벤트가 발생한 뷰의 Y좌표
  • rawX: 화면의 X좌표
  • rawY: 화면의 Y좌표
// 터치 이벤트가 발생한 좌표 얻기
override fun onTouchEvent(event: MotionEvent?): Boolean {
	when (event?.action) {
    	MotionEvent.ACTION_DOWN -> {
        	Log.d("kkang",
            	  "Touch down event x: ${event.x}, rawX: ${event.rawX}") // 매개변수로 좌표 얻음
        }
    }
    return super.onTouchEvent(event)
}

x와 rawX 모두 좌푯값이지만 의미하는 바는 다르다. x는 터치 이벤트가 발생한 뷰에서의 좌푯값, raw는 스크린, 즉 화면에서의 좌표값이다.

따라서 액티비티에 onTouchEvent() 함수를 재정의해서 작성했다면 x와 rawX의 값은 차이가 없다. 그런데 터치 이벤트는 특정 뷰에서도 처리할 수 있으므로 onTouchEvent() 함수를 어떤 뷰에 재정의했다면 x와 raw의 값은 차이가 있다

 

 

키 이벤트

키 이벤트는 사용자가 폰의 키를 누르는 순간에 발생한다. 액티비티에서 키 이벤트를 처리하려면 다음과 같이 콜백함수를 재정의해야 한다. 그러면 키 이벤트가 발생할 때 해당 함수가 자동으로 호출된다. 

onKeyDown: 키를 누른 순간의 이벤트

onKeyUp: 키를 떼는 순간의 이벤트

onKeyLongPress: 키를 오래 누르는 순간의 이벤트

// 키 이벤트 처리
class MainActivity2 : ApppCompatActivity() {
	(...생략...)
    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean { // 함수 재정의, 키 누를 때 처리
    	Log.d("kkang", "onKeyDown")
        return super.onKeyDown(keyCode, event)
    }
    override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean { // 키 뗄 때 처리
    	Log.d("kkang", "onKeyUp")
        return super.onKeyUp(keyCode, event)
    }
}

키 이벤트 함수의 첫번째 매개변수는 키의 코드이며 이 값으로 사용자가 어떤 키를 눌렀는지 식별할 수 있다.

// 어떤 키를 눌렀는지 식별
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
	when (keyCode) {
    	KeyEvent.KEYCODE_0 -> Log.d("kkang", "0 키를 눌렀네요") // 매개변수로 키의 코드 사용
    	KeyEvent.KEYCODE_A -> Log.d("kkang", "A 키를 눌렀네요")        
    }
    return super.onKeyDown(keyCode, event)
}

그런데 이러한 키 이벤트가 발생하는 키폰에서 제공하는 소프트 키보드의 키를 의미하지 않는다.(!!)

앱에서 글을 입력할 때 화면 아래에서 올라오는 키보드를 소프트 키보드(soft keyboard)라고 한다. 

소프트 키보드의 키는 키 이벤트로 처리할 수 없다. 즉, 액티비티에 onKeyDown() 등의 함수를 선언해 놓더라도 사용자가 소프트 키보드의 키를 눌렀을 때 이벤트 함수가 호출되지 않는다. 소프트 키보드는 안드로이드 시스템에 등록된 앱으로서 키를 누르면 글은 입력되지만 키 이벤트는 발생하지 않는다. 

그렇다면 키 이벤트는 '의미 없지 않을까?'라고 생각할 수 있다. 하지만 하드웨어 키보드가 있는 기기는 키보드의 키를 누르면 키 이벤트로 처리할 수 있다. 또한 안드로이드 시스템 버튼도 키로 취급하므로 이 버튼의 이벤트를 처리하는 데도 사용된다. 

안드로이드 폰은 전원버튼과 볼륨 조절 버튼을 대부분 가지고 있다. 뒤로가기, 홈, 오버뷰(최근에 사용한 앱 목록)도 있고 이 세 버튼을 포함하는 영역을 내비게이션 바(navigation bar)라고 한다. 내비게이션 바는 실행되는 앱과 상관없이 안드로이드 자체에서 제공하는 시스템 바이다. 

이 중에서 뒤로가기 버튼볼륨조절 버튼'키'로 취급해 이벤트로 처리할 수 있다. 그러나 전원, 홈, 오버뷰 버튼은 액티비티에 onKeyDown() 함수를 선언해 놓아도 사용자가 버튼을 눌렀을 때 함수가 호출되지 않는다. 즉, 앱에서 이벤트를 처리할 수 없는 버튼이다.

// 뒤로가기 버튼과 볼륨 조절 버튼의 이벤트 처리
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
	when (keyCode) {
    	KeyEvent.KEYCODE_BACK -> Log.d("kkang", "BACK Button을 눌렀네요") // 키 이벤트를 처리함
        KeyEvent.KEYCODE_VOLUME_UP -> Log.d("kkang", "Volume Up 키를 눌렀네요")
        KeyEvent.KEYCODE_VOLUME_DOWN -> Log.d("kkang", "Volume Down 키를 눌렀네요")
    }
    return super.onKeyDown(keyCode, event)
}

특별히 뒤로가기 버튼 이벤트에는 앞에서 살펴본 onKeyDown()이나 onKeyUp() 함수를 이용할 수도 있지만 onBackPressed() 함수를 이용할 수도 있다.

// 뒤로가기 버튼의 이벤트 처리
override fun onBackPressed() { // onKeyDown 함수 말고 다른 함수 씀
	Log.d("kkang", "Back Button을 눌렀네요")
}

그리고 API Level 33에서 뒤로 가기 버튼 이벤트 처리 함수인 OnBackPressed 함수는 deprecated 되었다. 현재는 androidx.activity.OnBackPressedCallback() 함수 이용을 권장하고 있으므로 이후 실습에서 deprecated() 메시지가 나오면 참고하길 바란다.

// 뒤로가기 버튼의 이벤트 처리
OnbackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
    override fun handleOnBackPressed() {
    
    }
})