본문 바로가기
Android Studio

안드로이드 #7 : 이벤트 처리하기 230303

by haheehee 2023. 3. 3.

터치 이벤트

- 터치 이벤트의 콜백 함수인 onTouchEvent()를 선언

- 매개변수는 MotionEvent 객체

- 이 객체에 터치의 종류와 발생 지점(좌푯값)이 담김

class MainActivity1 : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main1)
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        return super.onTouchEvent(event)
    }
}

 

터치 이벤트의 종류 

  • ACTION_DOWN: 화면을 손가락으로 누른 순간의 이벤트 
  • ACTION_UP: 화면에서 손가락을 떼는 순간의 이벤트
  • ACTION_MOVE: 화면을 손가락으로 누른 채로 이동하는 순간의 이벤트
override fun onToucEvent(event: MotionEvent?): Boolean {
	when(event?.action) {
    	MotionEvent.ACTION_DOWN -> {
        	Log.d("hahee", "Touch down event")
        }
    	MotionEvent.ACTION_UP -> {
        	Log.d("hahee", "Touch up event")
        }
    }
    return super.onTouchEvent(event)
}

 

터치 이벤트 발생 좌표 얻기

- onTouchEvent() 함수의 매개변수인 MotionEvent 객체로 획득

  • x: 이벤트가 발생한 뷰의 X 좌표
  • y: 이벤트가 발생한 뷰의 Y 좌표
  • rawX: 화면의 X 좌표 (모니터 시작지점 ~)
  • rawY: 화면의 Y 좌표 (모니터 시작지점 ~)
override fun onToucEvent(event: MotionEvent?): Boolean {
	when(event?.action) {
    	MotionEvent.ACTION_DOWN -> {
        	Log.d("hahee", "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("hahee", "onKeyDown")
    	return super.onKeyDown(keyCode, event)
    }
    
    override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
    	Log.d("hahee", "onKeyUp")
    	return super.onKeyUp(keyCode, event)
    }
}

 

- 첫 번째 매개변수는 키의 코드이며 이 값으로 사용자가 어떤 키를 눌렀는지 식별

override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
    when(keyCode) {
   		KeyEvent.KEYCODE_0 -> Log.d("hahee", "0 키를 눌렀네요")
        KeyEvent.KEYCODE_A -> Log.d("hahee", "A 키를 눌렀네요")
    }
    return super.onKeyDown(keyCode, event)
}

 

- 키 이벤트가 발생하는 키는 폰에서 제공하는 소프트 키보드의 키를 의미하지 않음

- 안드로이드 시스템 버튼도 키로 취급하므로 이 버튼의 이벤트를 처리

- 뒤로가기 버튼 이벤트에는 앞에서 살펴본 onKeyDown()이나 onKeyUp() 함수를 이용할 수도 있지만 onBackPressed() 함수를 이용할 수도 있음

override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
    when(keyCode) {
   		KeyEvent.KEYCODE_BACK -> Log.d("hahee", "BACK 키를 눌렀네요")
   		KeyEvent.KEYCODE_VOLUME_UP -> Log.d("hahee", "VOLUME_UP 키를 눌렀네요")
       	 KeyEvent.KEYCODE_VOLUME_DOWN -> Log.d("hahee", "VOLUME_DOWN 키를 눌렀네요")
    }
    return super.onKeyDown(keyCode, event)
}

뒤로가기와 볼륨 조절 버튼 이벤트 처리

override fun onBackPressed() {
    Log.d("hahee", "BACK 키를 눌렀네요")
}

뒤로가기 버튼의 이벤트 처리

 


뷰 이벤트의 처리 구조

- 뷰 이벤트 처리는 이벤트 소스와 이벤트 핸들러로 역할이 나뉘며 이 둘을 리스너로 연결해야 이벤트를 처리 가능

  • 이벤트 소스: 이벤트가 발생한 객체 
  • 이벤트 핸들러: 이벤트 발생 시 실행할 로직이 구현된 객체
  • 리스너: 이벤트 소스와 이벤트 핸들러를 연결해 주는 함수
binding.checkbox.setOnCheckedChangeListener(object: CompoundButton.OnCheckedChangeListener {
	override fun onCheckedChanged(p0: CompoundButton?, p1: Boolean) {
    	Log.d("hahee", "체크박스 클릭")
    }
})

체크 박스 이벤트 처리

- 이벤트 소스 : checkbox

- 리스너(이벤트 핸들러 등록) : setOnCheckedChangeListener

- object: 이벤트 핸들러

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

activity에서 interface 구현 예제

class MyEventHandler : CompoundButton.OnCheckedChangeListener {
	override fun onCheckedChanged(p0: CompoundButton?, p1: Boolean) {
    	Log.d("hahee", "체크박스 클릭")
    }
}
class MainActivity3 : AppCompatActivity() {
	override fun onCreate(savedInstanceState: Bundle?) {
    	super.onCreate(savedInstanceState)
        val binding = ActivityMain3Binding.inflate(layoutInflater)
        setContentView(binding.root)
        
        binding.checkbox.setOnCheckedChangeListener(MyEventHandler())
    }
}

이벤트 핸들러를 별도의 클래스로 만든 예제

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

SAM 기법으로 구현 예제


꼭 해당 모듈(ch8_event)의 build.gradle파일의

android {
    ...
    viewBinding {
        enabled = true
    }
}

android {...}안에 viewBinding { enabled=true }를 넣어주어야 한다.


클릭 이벤트 처리 예제 #1

package com.example.ch8_event

import android.os.Bundle
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import com.example.ch8_event.databinding.ActivityMain1Binding

class MainActivity1 : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = ActivityMain1Binding.inflate(layoutInflater)
        setContentView(binding.root)
        binding.btn.setOnClickListener {
            binding.btn.visibility = View.INVISIBLE
            binding.imgView.visibility = View.VISIBLE
        }
        binding.imgView.setOnClickListener {
            binding.btn.visibility = View.VISIBLE
            binding.imgView.visibility = View.INVISIBLE
        }
    }

}

MainActivity1

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <ImageView
        android:id="@+id/imgView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/mallang" />
    <Button
        android:id="@+id/btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="button1" />
</FrameLayout>

activity_main1.xml

 

꼭 manifest파일에서 MainActivity1으로 바꿔주어야 한다.(해당 파일로)

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.ch8_event">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.ProApplication">
        <activity
            android:name=".MainActivity1"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

 

- 결과 -

 


TOUCH_DOWN, TOUCH_UP 처리 예제 #2

package com.example.ch8_event

import android.os.Bundle
import android.util.Log
import android.view.MotionEvent
import androidx.appcompat.app.AppCompatActivity

class MainActivity3 : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main3)
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        when(event?.action) {
            MotionEvent.ACTION_DOWN -> {
                Log.d("hahee", "Touch down event")
            }
            MotionEvent.ACTION_UP -> {
                Log.d("hahee", "Touch up event")
            }
        }
        return super.onTouchEvent(event)
    }
}

MainActivity3

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <ImageView
        android:id="@+id/imgView2"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/mallang" />
</FrameLayout>

activity_main3.xml

 

manifest파일도 MainActivity3으로 바꿔주었다.

 

- 결과 -

밑의 Logcat에 Touch down event, Touch up event가 출력됨

 


TOUCH_DOWN 시 좌표값 얻기 예제 #3

package com.example.ch8_event

import android.os.Bundle
import android.util.Log
import android.view.MotionEvent
import androidx.appcompat.app.AppCompatActivity

class MainActivity4 : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main3)
    }

    override fun onTouchEvent(event: MotionEvent?): Boolean {
        when(event?.action) {
            MotionEvent.ACTION_DOWN -> {
                Log.d("hahee", "Touch down event x: ${event.x}, rawx : ${event.rawX}")
            }
        }
        return super.onTouchEvent(event)
    }
}

MainActivity4

 

manifest 를 MainActivity4로 수정해주었고, 

xml파일은 위 2번째 예제 그대로 activity_main3.xml을 사용하였다.

 

- 결과 -

밑에 Logcat에 좌표값이 찍힌다.

x, rawX

 

 


onKeyDown, onKeyUp 예제 #4

 

package com.example.ch8_event

import android.os.Bundle
import android.util.Log
import android.view.KeyEvent
import androidx.appcompat.app.AppCompatActivity

class MainActivity5 : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main3)
    }

    override fun onKeyDown(keyCode: Int, event: KeyEvent?): Boolean {
        Log.d("hahee", "onKeyDown")
        return super.onKeyDown(keyCode, event)
    }

    override fun onKeyUp(keyCode: Int, event: KeyEvent?): Boolean {
        Log.d("hahee", "onKeyUp")
        return super.onKeyUp(keyCode, event)
    }
}

MainActivity5

 

manifest 를 MainActivity5로 수정해주었고,

xml파일은 위 2번째 예제 그대로 activity_main3.xml을 사용하였다.

 

onKeyDown - 키를 누른 순간의 이벤트

onKeyUp: 키를 떼는 순간의 이벤트

 

- 결과 -

앱 실행 후, 

키보드를 사용하여 키를 입력해보면 밑에 onKeyDown, onKeyUp으로 이벤트가 발생하는 것을 확인할 수 있다.

 


checkbox 이벤트 예제 #5

package com.example.ch8_event

import android.os.Bundle
import android.util.Log
import android.widget.CompoundButton
import androidx.appcompat.app.AppCompatActivity
import com.example.ch8_event.databinding.ActivityMain6Binding

class MainActivity6 : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding = ActivityMain6Binding.inflate(layoutInflater)
        setContentView(binding.root)
        binding.checkbox1.setOnCheckedChangeListener(object : CompoundButton.OnCheckedChangeListener {
            override fun onCheckedChanged(buttonView: CompoundButton?, isChecked: Boolean) {
                Log.d("hahee", "체크박스를 클릭했습니다.")
            }
        })
    }
}

MainActivity6

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    <CheckBox
        android:id="@+id/checkbox1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</FrameLayout>

activity_main6.xml

 

manifest를 MainActivity6로 변경

 

- 결과 -

체크박스를 클릭함에 따라 Logcat에 해당 로그문이 출력된다.

 

 

 

 

 

 

댓글