앱의 화면에서 발생하는 사용자 이벤트는 touch다.
터치란 손가락으로 화면을 잠시 눌렀다가 떼는 행위이다.
앱은 보통 사용자의 터치를 인식하고 화면을 손가락으로 눌렀는지 떼었는지 swipe 했는지에 따라 다르게 동작하도록 구현한다.
class MainActivity : AppCompatActivity() {
override fun onTouchEvent(event: MotionEvent?): Boolean {
retrun super.onTouchEvent(event)
}
}
onTouchEvent() 함수를 재정의해서 선언만 해놓으면 사용자가 이 액티비티 화면을 터치하는 순간 onTouchEvent() 함수가 자동으로 호출된다.
x: 이벤트가 발생한 뷰의 X 좌표
y: 이벤트가 발생한 뷰의 Y 좌표
rawX: 화면의 X 좌표
rawY: 화면의 Y 좌표
package com.example.ch7_event
import android.os.Bundle
import android.view.MotionEvent
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
class MainActivity : AppCompatActivity() {
private lateinit var coordinatesText: TextView
private lateinit var mainLayout: ConstraintLayout
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
coordinatesText = findViewById(R.id.coordinatesText)
mainLayout = findViewById(R.id.mainLayout)
mainLayout.setOnTouchListener { _, event ->
when (event.action) {
MotionEvent.ACTION_DOWN, MotionEvent.ACTION_MOVE -> {
updateCoordinates(event)
true
}
else -> false
}
}
}
private fun updateCoordinates(event: MotionEvent) {
val x = event.x
val y = event.y
val rawX = event.rawX
val rawY = event.rawY
val message = """
Touch Coordinates:
x: %.2f, y: %.2f
rawX: %.2f, rawY: %.2f
""".trimIndent().format(x, y, rawX, rawY)
coordinatesText.text = message
}
}
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
android:id="@+id/mainLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="@+id/coordinatesText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Touch the screen"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
private lateinit var mainLayout: ConstraintLayout
에 대해:
lateinit
키워드의 의미:
onCreate()
메소드와 같이 생명주기 메소드에서 초기화될 변수에 사용된다.따로 설정한 이유:
findViewById()
는 setContentView()
이후에 호출해야 하므로, 클래스 레벨에서 바로 초기화할 수 없다.lateinit
을 사용함으로써 null 체크 없이 안전하게 사용할 수 있다.setOnTouchListener
가 Boolean을 반환하는 이유:
이는 안드로이드의 이벤트 처리 메커니즘과 관련이 있다.
반환값의 의미:
true
: 이벤트가 소비되었음을 의미. 이벤트 처리가 여기서 끝났다고 시스템에 알린다.false
: 이벤트가 소비되지 않았음을 의미. 다른 뷰나 상위 뷰가 이 이벤트를 처리할 수 있다.이유:
이벤트 전파 제어: true
를 반환하면 이벤트가 더 이상 전파되지 않는다.
예제에서의 사용:
ACTION_DOWN
과 ACTION_MOVE
에서는 true
를 반환하여 이벤트를 소비한다.false
를 반환하여 다른 뷰가 처리할 수 있게 한다.void
로 하지 않는 이유:
OnTouchListener
인터페이스가 boolean
을 반환하도록 미리 정의되어 있다.키 이벤트는 사용자가 폰의 키를 누르는 순간에 발생한다.
class MainActivity2: AppCompatActivity() {
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
Log.d(아무거나)
return super.onKeyDown(keyCode, event)
}
}
그런데 이러한 키 이벤트가 발생하는 키는 폰에서 제공하는 소프트 키보드의 키를 의미하지 않는다.
어떤 안드로이드 기기에는 하드웨어 키보드가 있다. 이런 하드웨어 키보드의 키를 입력하면 키 이벤트로 처리할 수 있다.
또한 안드로이드 폰의 뒤로가기 버튼과 볼륨 조절 버튼은 키로 취급하여, 키이벤트로 처리할 수 있다.
주의) 홈버튼, 오버뷰 버튼, 내비게이션 바, 전원 버튼은 키로 취급하지 않는다. 즉, 앱에서 이벤트를 처리할 수 없는 버튼이다.
package com.example.ch7_event
import android.os.Bundle
import android.view.KeyEvent
import android.widget.Toast
import androidx.activity.OnBackPressedCallback
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 뒤로가기 버튼 처리
val callback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
// 뒤로가기 버튼이 눌렸을 때의 동작
Toast.makeText(this@MainActivity, "뒤로가기 버튼이 눌렸습니다", Toast.LENGTH_SHORT).show()
// 여기서 앱을 종료하거나 다른 동작을 수행할 수 있습니다.
// 예: finish()
}
}
onBackPressedDispatcher.addCallback(this, callback)
}
// 볼륨 버튼 처리
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
return when (keyCode) {
KeyEvent.KEYCODE_VOLUME_UP -> {
Toast.makeText(this, "볼륨 올리기 버튼이 눌렸습니다", Toast.LENGTH_SHORT).show()
true
}
KeyEvent.KEYCODE_VOLUME_DOWN -> {
Toast.makeText(this, "볼륨 내리기 버튼이 눌렸습니다", Toast.LENGTH_SHORT).show()
true
}
else -> super.onKeyDown(keyCode, event)
}
}
}
import android.os.Bundle
import android.view.KeyEvent
import android.widget.Toast
import androidx.activity.OnBackPressedCallback
import androidx.appcompat.app.AppCompatActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 뒤로가기 버튼 처리
val callback = object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
// 뒤로가기 버튼이 눌렸을 때의 동작
Toast.makeText(this@MainActivity, "뒤로가기 버튼이 눌렸습니다", Toast.LENGTH_SHORT).show()
// 여기서 앱을 종료하거나 다른 동작을 수행할 수 있습니다.
// 예: finish()
}
}
onBackPressedDispatcher.addCallback(this, callback)
}
// 볼륨 버튼 처리
override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
return when (keyCode) {
KeyEvent.KEYCODE_VOLUME_UP -> {
Toast.makeText(this, "볼륨 올리기 버튼이 눌렸습니다", Toast.LENGTH_SHORT).show()
true
}
KeyEvent.KEYCODE_VOLUME_DOWN -> {
Toast.makeText(this, "볼륨 내리기 버튼이 눌렸습니다", Toast.LENGTH_SHORT).show()
true
}
else -> super.onKeyDown(keyCode, event)
}
}
}
뒤로가기 버튼 처리:
OnBackPressedCallback
객체를 생성하고 handleOnBackPressed()
메소드를 오버라이드한다.onBackPressedDispatcher
에 추가한다.볼륨 버튼 처리:
onKeyDown()
메소드를 오버라이드하여 키 이벤트를 처리한다.when
표현식을 사용하여 볼륨 올리기와 내리기 버튼을 구분한다.true
를 반환하여 이벤트가 처리되었음을 시스템에 알린다.토스트 메시지, 또는 토스트란, 사용자에게 짧은 메시지 형식으로 정보를 전달하는 팝업을 의미한다. 메시지를 표시할 공간만 차지하고 시간이 지나면 자동으로 사라진다.
뒤로가기버튼은 OnBackPressedCallback
함수를 사용하는 것이 최근 트렌드라고 한다.
onBackPressedDispatcher는 Android에서 뒤로 가기 버튼을 처리하기 위한 시스템이다. 주로 AndroidX 라이브러리에서 제공되며, 액티비티나 프래그먼트에서 뒤로 가기 버튼을 커스텀하게 제어할 때 사용된다. 기존에는 onBackPressed() 메서드를 오버라이드해서 뒤로 가기 버튼을 처리했지만, onBackPressedDispatcher를 사용하면 더 유연하게 여러 구성요소에서 뒤로 가기 이벤트를 관리할 수 있다.
onTouchEvent()
메서드로 처리한다.ACTION_DOWN
, ACTION_UP
, ACTION_MOVE
.x
, y
(뷰 기준), rawX
, rawY
(화면 기준).OnTouchListener
로 터치 이벤트를 처리한다.onKeyDown()
, onKeyUp()
, onKeyLongPress()
.onBackPressedDispatcher
를 사용해 뒤로가기 버튼을 유연하게 관리할 수 있다.onBackPressedDispatcher
는 뒤로가기 버튼 처리를 위한 현대적 방법이다.