사용자 이벤트 처리하기 - 터치와 키 이벤트

이윤설·2024년 8월 26일
0

터치 이벤트

앱의 화면에서 발생하는 사용자 이벤트는 touch다.
터치란 손가락으로 화면을 잠시 눌렀다가 떼는 행위이다.

앱은 보통 사용자의 터치를 인식하고 화면을 손가락으로 눌렀는지 떼었는지 swipe 했는지에 따라 다르게 동작하도록 구현한다.

class MainActivity : AppCompatActivity() {
  override fun onTouchEvent(event: MotionEvent?): Boolean {
    retrun super.onTouchEvent(event)
    }
  }

onTouchEvent() 함수를 재정의해서 선언만 해놓으면 사용자가 이 액티비티 화면을 터치하는 순간 onTouchEvent() 함수가 자동으로 호출된다.

종류

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

터치이벤트 발생 좌표 얻기


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>

  1. XML 레이아웃에서는 전체 화면을 차지하는 ConstraintLayout과 중앙에 위치한 TextView를 정의한다.
  2. MainActivity에서는 화면 전체(mainLayout)에 터치 리스너를 설정한다.
  3. 사용자가 화면을 터치하거나 드래그할 때(ACTION_DOWN 또는 ACTION_MOVE), updateCoordinates 함수가 호출된다.
  4. updateCoordinates 함수는 터치 이벤트의 x, y, rawX, rawY 좌표를 가져와 TextView에 표시한다.

이모저모

  1. private lateinit var mainLayout: ConstraintLayout에 대해:

    • lateinit 키워드의 의미:

      • "나중에 초기화"를 의미한다.
      • 코틀린에서 non-null 타입의 프로퍼티를 선언 시점에 초기화하지 않고, 나중에 초기화할 수 있게 해준다.
      • 주로 안드로이드의 onCreate() 메소드와 같이 생명주기 메소드에서 초기화될 변수에 사용된다.
    • 따로 설정한 이유:

      • 레이아웃 전체에 터치 리스너를 적용하기 위해 레이아웃에 대한 참조가 필요하다.
      • findViewById()setContentView() 이후에 호출해야 하므로, 클래스 레벨에서 바로 초기화할 수 없다.
      • lateinit을 사용함으로써 null 체크 없이 안전하게 사용할 수 있다.
  2. setOnTouchListener가 Boolean을 반환하는 이유:

    • 이는 안드로이드의 이벤트 처리 메커니즘과 관련이 있다.

    • 반환값의 의미:

      • true: 이벤트가 소비되었음을 의미. 이벤트 처리가 여기서 끝났다고 시스템에 알린다.
      • false: 이벤트가 소비되지 않았음을 의미. 다른 뷰나 상위 뷰가 이 이벤트를 처리할 수 있다.
    • 이유:
      이벤트 전파 제어: true를 반환하면 이벤트가 더 이상 전파되지 않는다.

    • 예제에서의 사용:

      • ACTION_DOWNACTION_MOVE에서는 true를 반환하여 이벤트를 소비한다.
      • 다른 액션에서는 false를 반환하여 다른 뷰가 처리할 수 있게 한다.
    • void로 하지 않는 이유:

      • 안드로이드의 OnTouchListener 인터페이스가 boolean을 반환하도록 미리 정의되어 있다.

키 이벤트

키 이벤트는 사용자가 폰의 키를 누르는 순간에 발생한다.

  • onKeyDown: 키를 누른 순간의 이벤트
  • onKeyUp: 키를 떼는 순간의 이벤트
  • onKeyLongPress: 키를 오래 누르는 순간의 이벤트
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)
        }
    }
}
  1. 뒤로가기 버튼 처리:

    • OnBackPressedCallback 객체를 생성하고 handleOnBackPressed() 메소드를 오버라이드한다.
    • 이 콜백을 onBackPressedDispatcher에 추가한다.
    • 뒤로가기 버튼이 눌리면 토스트 메시지를 표시한다.
  2. 볼륨 버튼 처리:

    • onKeyDown() 메소드를 오버라이드하여 키 이벤트를 처리한다.
    • when 표현식을 사용하여 볼륨 올리기와 내리기 버튼을 구분한다.
    • 각 버튼에 대해 토스트 메시지를 표시한다.
    • true를 반환하여 이벤트가 처리되었음을 시스템에 알린다.

이모저모 2

  • 토스트 메시지, 또는 토스트란, 사용자에게 짧은 메시지 형식으로 정보를 전달하는 팝업을 의미한다. 메시지를 표시할 공간만 차지하고 시간이 지나면 자동으로 사라진다.

  • 뒤로가기버튼은 OnBackPressedCallback 함수를 사용하는 것이 최근 트렌드라고 한다.

  • onBackPressedDispatcher는 Android에서 뒤로 가기 버튼을 처리하기 위한 시스템이다. 주로 AndroidX 라이브러리에서 제공되며, 액티비티나 프래그먼트에서 뒤로 가기 버튼을 커스텀하게 제어할 때 사용된다. 기존에는 onBackPressed() 메서드를 오버라이드해서 뒤로 가기 버튼을 처리했지만, onBackPressedDispatcher를 사용하면 더 유연하게 여러 구성요소에서 뒤로 가기 이벤트를 관리할 수 있다.

요약

터치 이벤트 요약

  • 터치 이벤트는 화면을 눌렀을 때 발생하며 onTouchEvent() 메서드로 처리한다.
  • 주요 이벤트: ACTION_DOWN, ACTION_UP, ACTION_MOVE.
  • 이벤트 발생 좌표: x, y (뷰 기준), rawX, rawY (화면 기준).
  • XML 레이아웃과 OnTouchListener로 터치 이벤트를 처리한다.

키 이벤트 요약

  • 키 이벤트는 하드웨어 키보드와 폰의 뒤로가기, 볼륨 버튼 등을 처리한다.
  • 주요 메서드: onKeyDown(), onKeyUp(), onKeyLongPress().
  • onBackPressedDispatcher를 사용해 뒤로가기 버튼을 유연하게 관리할 수 있다.
  • 터치와 키 이벤트는 사용자 입력을 처리하는 핵심 요소로, 좌표와 이벤트 종류에 따라 앱 동작을 제어한다.
  • onBackPressedDispatcher는 뒤로가기 버튼 처리를 위한 현대적 방법이다.
profile
화려한 외면이 아닌 단단한 내면

0개의 댓글