[Do it! 깡샘의 안드로이드 앱 프로그래밍 with 코틀린] 사용자 이벤트 처리하기

안드로이드 앱 프로그래밍에서 사용자 이벤트를 처리하는 방법을 정리했다. 터치 이벤트는 onTouchEvent() 콜백 함수를 재정의하여 처리하며, 주요 이벤트로는 ACTION_DOWN, ACTION_UP, ACTION_MOVE가 있다. 키 이벤트는 onKeyDown, onKeyUp, onKeyLongPress 콜백 함수로 처리하며, 특정 키 이벤트는 onBackPressed()를 사용할 수 있다. 뷰 이벤트는 이벤트 소스와 핸들러를 리스너로 연결하여 처리하며, 클릭과 롱클릭 이벤트는 각각 setOnClickListener와 setOnLongClickListener로 처리한다. 코틀린의 SAM 기법을 사용하면 이벤트 핸들러를 간단하게 작성할 수 있다.
DriedPollack's avatar
Jul 18, 2024
[Do it! 깡샘의 안드로이드 앱 프로그래밍 with 코틀린] 사용자 이벤트 처리하기

🌼터치와 키 이벤트

💡터치 이벤트

  • 앱의 화면에서 발생하는 사용자의 터치 이벤트를 처리하고 싶다면 액티비티 클래스에 터치 이벤트의 콜백 함수인 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() 매개변수를 통해 좌표를 얻어 판단해야 하는 등 뷰가 많을 때는 프로그래밍이 복잡해진다.
  • 뷰 이벤트는 이벤트 콜백 함수만 선언해서는 처리할 수 없다.
    • 뷰 이벤트 처리는 이벤트 소스와 이벤트 핸들러로 역할이 나뉘며 이 둘을 리스너로 연결해야 이벤트를 처리할 수 있다.
      • notion image
    • 이벤트 소스 : 이벤트가 발생한 객체
    • 이벤트 핸들러 : 이벤트 발생 시 실행할 로직이 구현된 객체
    • 리스너 : 이벤트 소스와 이벤트 핸들러를 연결해 주는 함수
    • 다음 코드는 체크박스의 체크 상태가 변경될 때 이벤트 처리를 작성한 것이다.
      • 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는 길게 클릭할 때 발생한다.
  • ClickEventLongClickEvent는 최상위 클래스인 View에 정의된 이벤트다. 두 이벤트의 핸들러는 다음과 같다.
    • open fun setOnClickListener(l:View.OnClickListener?): Unit
    • open fun setOnLongClickListener(l:View.OnLongClickListener?): Unit
  • ClickEventOnClickListener를 구현한 객체를 이벤트 핸들러로 등록해야 하고 LongClickEventOnLongClickListener를 구현한 객체를 이벤트 핸들러로 등록해야 한다.
    • // 버튼의 클릭, 롱클릭 이벤트 처리 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?){ } }
    • 코틀린의 SAM 기법을 이용하면 이 코드를 좀 더 간단하게 작성할 수 있다. SAM은 자바 API를 코틀린에서 활용할 때 람다 표현식으로 쉽게 이용할 수 있게 해주는 기법이다.
      • 예를 들어 다음과 같은 자바 인터페이스가 있다고 가정해보자.
        • // 자바 인터페이스 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()를 사용할 수 있다. 뷰 이벤트는 이벤트 소스와 핸들러를 리스너로 연결하여 처리하며, 클릭과 롱클릭 이벤트는 각각 setOnClickListenersetOnLongClickListener로 처리한다. 코틀린의 SAM 기법을 사용하면 이벤트 핸들러를 간단하게 작성할 수 있다.
Share article

More articles

See more posts

👨🏻‍💻DriedPollack's Blog