[Do it! 깡샘의 안드로이드 앱 프로그래밍 with 코틀린] 사용자 이벤트 처리하기
안드로이드 앱 프로그래밍에서 사용자 이벤트를 처리하는 방법을 정리했다. 터치 이벤트는 onTouchEvent() 콜백 함수를 재정의하여 처리하며, 주요 이벤트로는 ACTION_DOWN, ACTION_UP, ACTION_MOVE가 있다. 키 이벤트는 onKeyDown, onKeyUp, onKeyLongPress 콜백 함수로 처리하며, 특정 키 이벤트는 onBackPressed()를 사용할 수 있다. 뷰 이벤트는 이벤트 소스와 핸들러를 리스너로 연결하여 처리하며, 클릭과 롱클릭 이벤트는 각각 setOnClickListener와 setOnLongClickListener로 처리한다. 코틀린의 SAM 기법을 사용하면 이벤트 핸들러를 간단하게 작성할 수 있다.
Jul 18, 2024
🌼터치와 키 이벤트
💡터치 이벤트
- 앱의 화면에서 발생하는 사용자의 터치 이벤트를 처리하고 싶다면 액티비티 클래스에 터치 이벤트의 콜백 함수인
onTouchEvent()
를 재정의하면 된다.
class MainActivity : AppCompatActivity() { (...생략...) override fun onTouchEvent(event: MotionEvent?): Boolean { return super.onTouchEvent(event) } }
onTouchEvent()
를 재정의해서 선언만 해놓으면 사용자가 이 액티비티 화면을 터치하는 순간 onTouchEvent()
함수가 자동으로 호출된다.MotionEvent
객체이며, 이 객체에 터치의 종류와 발생 지점(좌푯값)이 담긴다.- 터치 이벤트는 다음 3가지로 나뉜다.
ACTION_DOWN
: 화면을 손가락으로 누른 순간의 이벤트ACTION_UP
: 화면에서 손가락을 뗀 순간의 이벤트ACTION_MOVE
: 화면을 손가락으로 누른 채로 이동하는 순간의 이벤트
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) }
- 터치 이벤트를 처리할 때에는 이벤트의 종류뿐만 아니라 이벤트가 발생한 지점을 알아야 하는 경우도 있다. 이 좌표도
onTouchEvent()
의MotionEvent
객체로 얻는다. x
: 이벤트가 발생한 뷰의 X 좌표y
: 이벤트가 발생한 뷰의 Y 좌표rawX
: 화면의 X 좌표rawY
: 화면의 Y 좌표
💡키 이벤트
- 키 이벤트는 사용자가 폰의 키를 누르는 순간에 발생한다. 액티비티에서 키 이벤트를 처리하려면 콜백 함수를 재정의해야 한다.
- 키 이벤트는 다음 3가지로 나뉜다.
onKeyDown
: 키를 누른 순간의 이벤트onKeyUp
: 키를 떼는 순간의 이벤트onKeyLongPress
: 키를 오래 누르는 순간의 이벤트
- 키 이벤트 함수의 첫 번째 매개변수는 키의 코드이며 이 값으로 사용자가 어떤 키를 눌렀는지 식별할 수 있다.
- 이런 키 이벤트가 발생하는 키는 폰에서 제공하는
소프트 키보드
의 키를 의미하지 않는다. - 키 이벤트가 발생하는 키는 전원 버튼, 볼륨 조절 버튼, 내비게이션 바(뒤로 가기, 홈, 오버뷰 버튼)가 있다.
- 전원, 홈, 오버뷰 버튼은 액티비티에
onKeyDown()
함수를 선언해도 사용자가 버튼을 눌렀을 때 함수가 호출되지 않는다. - 뒤로 가기 버튼 이벤트의 경우
onKeyDown()
이나onKeyUp()
말고도onBackPressed()
함수를 이용할 수도 있다.
API Level 33에서 onBackPressed() 함수는 deprecated 되었으므로 androidx.activity.OnBackPressedCallBack() 함수 이용이 권장된다.
뒤로 가기 버튼의 이벤트 처리는 앱의 첫 화면에서 뒤로 가기 버튼을 눌렀을 때 앱이 종료되지 않고 한 번 더 누르라는 메시지를 출력하는 데 사용될 수 있다.
🌼뷰 이벤트
💡뷰 이벤트의 처리 구조
- 뷰를 사용자가 터치했을 때 이벤트 처리는 터치 이벤트를 이용하지 않는다.
뷰의 이벤트도 터치 이벤트로 처리할 수 있지만 프로그래밍이 복잡해질 수 있다.
예를 들어 다른 종류의 뷰가 여러개 있는 액티비티에서 터치 이벤트로 처리를 할 경우, 어떤 뷰를 터치했는지 알기 위해서 onTouchEvent() 매개변수를 통해 좌표를 얻어 판단해야 하는 등 뷰가 많을 때는 프로그래밍이 복잡해진다.
- 뷰 이벤트는 이벤트 콜백 함수만 선언해서는 처리할 수 없다.
- 뷰 이벤트 처리는 이벤트 소스와 이벤트 핸들러로 역할이 나뉘며 이 둘을 리스너로 연결해야 이벤트를 처리할 수 있다.
이벤트 소스
: 이벤트가 발생한 객체이벤트 핸들러
: 이벤트 발생 시 실행할 로직이 구현된 객체리스너
: 이벤트 소스와 이벤트 핸들러를 연결해 주는 함수- 다음 코드는 체크박스의 체크 상태가 변경될 때 이벤트 처리를 작성한 것이다.
binding.checkBox.setOnCheckedChangeLstener(object: CompoundButton.OnCheckedChangeListener{ override fun onCheckedChanged(p0: CompoundButton?, p1: Boolean){ Log.d("kkang","체크박스 클릭") } }
checkbox
객체가 이벤트가 발생하는 이벤트 소스이며, 이벤트 처리 내용이 담긴 이벤트 핸들러는 OnCheckedChangeListener
인터페이스를 구현한 객체인 object
고, setOnCheckedChangeListener()
함수는 이벤트 핸들러를 등록하는 리스너다.- 인터페이스를 구현한 object 클래스를 이벤트 핸들러로 만들었지만, 액티비티 자체에서 인터페이스를 구현할 수도 있다. 또한 이벤트 핸들러를 별도의 클래스로 만들어 처리할 수도 있으며 코틀린의
SAM
기법을 이용할 수도 있다.
// 액티비티에서 인터페이스를 구현한 예 class MainActivity3 : AppCompatActivity(), CompoundButton.OnCheckedChangeListener { override fun onCreate(savedInstanceState: Bundle?){ super.onCreate(savedInstanceState) val binding = ActivityMain3Binding.inflate(layoutInflater) setContentView(binding.root) binding.checkbox.setOnCheckedChangeLstener(this) } override fun onCheckedChanged(p0: CompoundButton?, p1: Boolean){ Log.d("kkang","체크박스 클릭") } } // 이벤트 핸들러를 별도의 클래스로 만든 예 class MyEventHandler : CompoundButton.OnCheckedChangeListener { override fun onCheckedChanged(p0: CompoundButton?, p1: Boolean){ Log.d("kkang","체크박스 클릭") } } class MainActivity3 : AppCompatActivity(){ override fun onCreate(savedInstanceState: Bundle?){ super.onCreate(savedInstanceState) val binding = ActivityMain3Binding.inflate(layoutInflater) setContentView(binding.root) binding.checkbox.setOnCheckedChangeLstener(MyEventHandler()) } } // SAM 기법으로 구현한 예 class MainActivity3 : AppCompatActivity(){ override fun onCreate(savedInstanceState: Bundle?){ super.onCreate(savedInstanceState) val binding = ActivityMain3Binding.inflate(layoutInflater) setContentView(binding.root) binding.checkbox.setOnCheckedChangeLstener{ compoundButton, b -> Log.d("kkang","체크박스 클릭") } } }
💡클릭과 롱클릭 이벤트 처리
- 안드로이드는 앱의 화면을 구성하는 데 필요한 다양한 뷰를 제공하며 대부분 뷰에서 자체 이벤트를 제공한다.
- 뷰가 아무리 많아도 이벤트 처리 구조는 동일하다.
- 따라서 이벤트 소스와 이벤트 핸들러를 리스너로 연결하는 구조만 이해한다면 어떤 뷰 이벤트라도 어렵지 않게 처리할 수 있다.
ClickEvent
는 뷰를 짧게 클릭할 때 발생하고,LongClickEvent
는 길게 클릭할 때 발생한다.
ClickEvent
와LongClickEvent
는 최상위 클래스인View
에 정의된 이벤트다. 두 이벤트의 핸들러는 다음과 같다.open fun setOnClickListener(l:View.OnClickListener?): Unit
open fun setOnLongClickListener(l:View.OnLongClickListener?): Unit
ClickEvent
는OnClickListener
를 구현한 객체를 이벤트 핸들러로 등록해야 하고LongClickEvent
는OnLongClickListener
를 구현한 객체를 이벤트 핸들러로 등록해야 한다.
// 버튼의 클릭, 롱클릭 이벤트 처리 binding.button.setOnClickListener{ Log.d("kkang","클릭 이벤트") } binding.button.setOnLongClickListener{ Log.d("kkang","롱클릭 이벤트") true }
롱클릭 이벤트 핸들러에서 마지막 줄의 true를 생략하면 오류가 발생한다.
LongClickEvent의 콜백 함수는 반환값이 Boolean이므로 true나 false를 반환해야 하는데, 람다 함수는 본문이 여러 줄이면 마지막 줄의 실행 결과를 반환하므로, return 예약어를 사용하지 않는다.
- 뷰 이벤트 처리 구조를 보면 이벤트 핸들러는
setOnClickListener()
함수로 등록하고, 여기에OnClickListener
인터페이스를 구현한 객체를 지정해야 하는데, 위 코드는 그냥setOnClickListener
에 람다 함수를 매개변수로 지정한 것처럼 보인다. - 예를 들어 이벤트 핸들러를 자바와 코틀린으로 작성한다면 다음처럼 작성할 수 있다.
// 자바로 작성한 이벤트 핸들러 binding.btn.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View view){ } } // 코틀린으로 전환한 이벤트 핸들러 binding.btn.setOnclickListener(object: View.OnClickListener{ override fun onClick(p0: View?){ } }
- 예를 들어 다음과 같은 자바 인터페이스가 있다고 가정해보자.
// 자바 인터페이스 public interface JavaInterface1{ void callback(); }
// 자바 함수 public class SAMTest{ JavaInterface1 callback; public void setInterface(JaveInterface1 callback){ this.callback - callback; } }
setInterface()
를 코틀린에서 이용할려면 인터페이스를 구현한 객체를 매개변수로 지정해야 한다. 또는 SAM 기법을 이용하면 더 간결하게 작성할 수 있다.// 코틀린에서 자바 함수 사용 obj.setInterface(object: JavaInterface1{ override fun callback(){ println("hello kotlin") } } // SAM 기법을 이용한 자바 함수 호출 obj.setInterface { println("hello SAM") } // SAM 기법을 이용한 이벤트 핸들러의 구조 binding.btn.setOnClickListener{ (...생략...) }
🏁결론
안드로이드 앱 프로그래밍에서 사용자 이벤트를 처리하는 방법을 정리했다. 터치 이벤트는
onTouchEvent()
콜백 함수를 재정의하여 처리하며, 주요 이벤트로는 ACTION_DOWN
, ACTION_UP
, ACTION_MOVE
가 있다. 키 이벤트는 onKeyDown
, onKeyUp
, onKeyLongPress
콜백 함수로 처리하며, 특정 키 이벤트는 onBackPressed()
를 사용할 수 있다. 뷰 이벤트는 이벤트 소스와 핸들러를 리스너로 연결하여 처리하며, 클릭과 롱클릭 이벤트는 각각 setOnClickListener
와 setOnLongClickListener
로 처리한다. 코틀린의 SAM 기법을 사용하면 이벤트 핸들러를 간단하게 작성할 수 있다.Share article