• 사용자 이벤트 처리하기

화면에 출력되는 뷰에서 발생하는 이벤트를 처리하거나, 뒤로가기 버튼 같은 안드로이드 시스템의 키 이벤트를 처리하는 방법


08-1 터치와 키 이벤트

터치 이벤트

앱의 화면에서 발생하는 사용자 이벤트는 터치(Touch)입니다.

사용자의 터치 이벤트를  처리하고 싶다면 액티비티 클레스에 터치 이벤트의 콜백 함수인 onTouchEvenet()를 선언하면 됩니다.

(콜백 함수란 어떤 이벤트가 발생하거나 시점에 도달했을 때 시스템에서 자동으로 호출하는 함수를 말합니다.)

class MainActivity: AppComaptActivity(){
	...
    override fun onTouchEvent(event: MotionEvent?): boolean{
    	return super.onTouchEvent(event)
    }
}

onTouchEvent()함수를 재정의 해서 선언만 해놓으면 액티비티 화면을 터치하는 순간 onTouchEvent()함수가 호출됩니다.

매개변수 MotionEvent객체는 터치의 종류와 발생지점(좌푯값)이 담깁니다.

 

터치이벤트의 종류

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

화면을 손가락으로 눌렀다 때면 onTouchEvent()함수는 2번 호출됩니다. DOWN → UP

손가락을 이동후 떼었다면 3번 호출됩니다. DOWN → MOVE → UP

override fun onTouchEvent(event: MotionEvent?): Boolean{
	when(event?.action){
    	MotionEvent.ACTION_DOWN ->{
        	Log.d("down", "TOUCH DOWN EVENT")
        }
        MotionEvent.ACTION_UP -> {
        	Log.d("up", "TOUCH UP EVENT")
        }
    }
    return super.OnTouchEvent(event)
}

 

터치 이벤트 발생 좌표 얻기

이벤특가 발생한 지점을 알아야 하는 경우 onTouchEvent()함수의 매개변수인 MotionEvent객체로 얻습니다.

  • x: 이벤트가 발생한 뷰의 X좌표
  • y: 이벤트가 발생한 뷰의 Y좌표
  • rawX: 화면의 X좌표
  • rawY: 화면의 Y좌표
override fun onTouchEvent(event: MotionEvent?): Boolean{
	when (event.action){
    	MotionEvent.ACTION_DOWN->{
        	Log.d("down",
            	"Touch down event x: ${event.x}, rawX: ${event.rawX}")
        }
    }
    return super.onTouchEvent(event)
}

 

키 이벤트

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

키 이벤트를 처리하려면 다음과 같이 콜백 함수를 재정의해야 합니다. 그러면 키 이벤트가 발생할 때 해당 함수가 자동으로 호출됩니다.

  • onKeyDown: 키를 누른 순간의 이벤트
  • onKeyUp: 키를 떼는 순간의 이벤트
  • onKeyLongPress: 키를 오래 누르는 순간의 이벤트
class MainActivity2: AppCompatActivity(){
	...
    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
    	Log.d("down", "onKeydown")
        return super.onKeyDown(keyCode, event)
    }  
}

 

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

override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
	when(keyCode){
    	KeyEvent.KEYCODE_0 -> Log.d("kkang", "0키 누름")
    }
    return super.onKeyDown(keyCode,event)
}

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

하드웨어 키보드를 갖는 안드로이드 기기나 시스템 버튼을 키로 취급하므롤 이 버튼의 이벤트를 처리하는 데도 사용됩니다.

(전원 버튼, 볼륨 버튼, 뒤로가기, 홈, 오버뷰-네비게이션 바 등)

 

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

 

(뒤로가기 버튼은 onBackPressed()를 사용했으나 deprecated되어 현재는 androidx.activity.OnBackPressedCallback()함수 이용을 권장함)

 

08-2 뷰 이벤트

액티비티 화면은 TextView, EditText, ImageView, Button등의 뷰로 화면을구성하고 구현합니다.

이런 뷰를 사용자가 터치했을 때 이벤트 처리는 앞에서 살펴본 터치 이벤트를 이용하지 않습니다. 각 뷰에서 이벤트를 별도로 제공합니다.

뷰 이벤트의 처리 구조

뷰 이벤트에서는 이벤트 콜백 함수만 선언해서는 처리할 수 없습니다.

뷰 이벤트 처리는 이벤트 소스와 이벤트 핸들러를 리스너로 연결해야 합니다.

  • 이벤트 소스: 이벤트가 발생한 객체
  • 이벤트 핸들러: 이벤트 발생 시 실행할 로직이 구현된 객체
  • 리스너: 이벤트 소스와 이벤트 핸들러를 연결해 주는 함수

이벤트 소스에 리스너로 이벤트 핸들러를 등록해 놓으면 이벤트가 발생할 때 실행되는 구조입니다.

binding.checkbox.setOnCheckedChangeListener(object: CompoundButton.OnCheckedChangeListener{
	override fun onCheckedChanged(p0: CompoundButton?, p1: Boolean){
    	Log.d("check", "체크박스 클릭")
    }
}

checkbox객체가 이벤트가 발생하는 이벤트 소스, 처리 내용이 담긴 이벤트 핸들러는 OnCheckedChangeListener 인터페이스를 구현한 객체입니다.

대부분 이벤트 핸들러는 이름 형식이 OnXXXListener인 인터페이스를 구현해서 만듭니다.

인터페이스를 구현한 object클래스를 이벤트 핸들러로 만들었지만, 액티비티 자체에서 인터페이스를 구현할 수도 있습니다.

혹은 이벤트 핸들러를 별도의 클래스로 만들어 처리할 수도 있으며 코틀린의 SAM(Single Abstract Method)기법을 이용할 수도 있습니다.

 

액티비티 자체에서 인터페이스 구현하기

class MainActivity: AppCompatActivity(), CompoundButton. OnCheckedChangeListener{
	override fun onCreate(savedInstancesState: Bundle?){
    	super.onCreate(savedInstanceState)
        val binding = ActivityMain3Binding.inflate(layoutInflater)
        steContentView(binding.root)
        binding.checkbox.setOnCheckedListener(this)
    }
    override fun onCheckedChanged(p0: CompoundButton?, p1: Boolean){
    	Log.d("click", "체크박스 클릭")
    }
}

 

 

이벤트 핸들러를 별도의 클래스로 만들기

class MyEventHandler: CompoundButton.OncheckedListener{
	override fun onCheckedChanged(p0: CompoundButton?, p1: Boolean){
    	Log.d("click", "체크박스 클릭")
    }
}

class MainActivity3: AppCompatActivity(){
	override fun onCreate(savedInstanceState: Bundle?){
    	super.onCreate(savedInstanceState)
        val binding = ActivityMain3Binding.inflate(layoutInflater)
        setContentView(binding.root)
        
        binding.checkbox.setOnCheckedChangeListener(MyEventHandler())
    }
}

 

 

SAM기법으로 구현하기

class MainActivity3: AppCompatActivity(){
	override fun onCreate(savedInstanceState: Bundle?){
    	super.onCreate(savedInstanceState)
        
        val binding = ActivityMain3Binding.infalte(layoutInflater)
        setContentView(binding.root)
        
        binding.checkbox.setOnCheckedChangelistener{
        	compoundButton, b ->
            Log.d("click", "체크박스 클릭")
        }
    }
}

 

클릭과 롱클릭 이벤트 처리

안드로이드는 앱을 위한 다양한 뷰를 제공하며 자체 이벤트도 존재합니다.

그러나 뷰가 아무리 많아도 이벤트처리 구조는 같아 이벤트 소스와 이벤트 핸들러를 리스너로 연결하는 구조만 이해한다면 어떤 뷰 이벤트라도 처리할 수 있습니다.

 

대표적으로 뷰를 짧게 클릭할때 발생하는 ClickEvent와 길게 클릭할 때 발생하는 LongClickEvent에 대해 알아봅니다.

ClickEvent, LongClickEvent는 뷰의 최상위 클래스인 View에 정의된 이벤트입니다.

즉 가장 기초이면서 많이 이용하는 이벤트입니다. 핸들러는 다음과 같습니다.

  • open fun setOnClickListener(l: View.OnClickListener?): Unit
  • open fun setOnLongClickListener(l: View.OnLongClickListener?): Unit

각 이벤트는 해당 리스너를 구현한 객체를 이벤트 핸들러로 등록해야 합니다.

binding.button.setOnClickListener{
	Log.d("click", "클릭 이벤트")
}

binding.button.setOnLongClickListener{
	Log.d("click", "롱클릭 이벤트")
    true
}

위 코드를 보면 setOnClickListener() 함수를 이벤트 핸들러로 등록하고 OnClickListner이벤트를 구현한 객체를 지정해야 하는데, 람다 함수를 매개변수로 지정한 것처럼 보입니다.

 

자바 코드로 작성하면 다음과 같습니다.

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(JavaInterface1 callback){
    	this.callback = callback;
    }
}

위처럼 setInterfact를 코틀린에서 이용하려면 인터페이스를 구현한 객체를 매개변수로 지정해야하므로 다음과같이 작성할 수 있습니다.

obj.setInterface(object: JavaInterface1{
	override fun callback(){
    	println("hello kotlin")
    }
})

이를 SAM 기법을 이용하면 아래와같이 작성됩니다.

obj.setInterface{println("hello SAM")}

 

모든 자바 인터페이스를 구현한 객체를 SAM으로 활용할 수 있는것은 아니지만, 대부분의 이벤트 핸들러 등록 코드를 다음처럼 작성할 수 있습니다.

binding.btn.setOnClickListener{
	...
}

08-3 시계 앱의 스톱워치 기능 만들기

(실습)

'Java > Kotlin' 카테고리의 다른 글

Kotlin Programming Study - 09  (0) 2025.12.19
Kotlin Programming Study - 07  (0) 2025.12.16
Kotlin Programming Study - 06  (0) 2025.12.15
Kotlin Programming Study - 04  (0) 2025.12.10
Kotlin Programming Study - 03  (0) 2025.12.09

+ Recent posts