[Android] - TouchEvent

명준쓰·2023년 6월 27일
0

안녕하세요 오늘은 터치 이벤트에 대해 포스팅 해보려고 합니다.

이번에 회사 프로젝트로 태블릿 pc 용 어플리케이션을 만드는 작업을 진행하며 TouchEvent에 대해 공부하며 공부한 내용들을 포스팅 해보겠습니다.

터치 이벤트란?

터치 이벤트는 사용자가 화면을 터치하거나 터치를 움직이는 등의 동작을 할 때 발생하는 이벤트 입니다.

Touch와 Click은 비슷하면서도 다릅니다.

Click은 단일 액션을 처리하는데 주로 사용되고 눌럿다가 떼는 순간에만 반응합니다.
Touch는 사용자의 터치 동작을 다양하게 처리해 액션 다운, 이동, 업 등의상태를 포함하여 좀 더 상세한 터치 정보를 제공합니다.

TouchEvent가 발생하면 모든 이벤트 발생 알림의 시작점은 액티비티부터 시작됩니다.
Activity -> ViewGroup -> View 순으로 Notify 됩니다.
이벤트의 처리는 알림의 역순입니다.

자주 쓰이는 터치의 MotionEvent에 대해 알아보겠습니다.

MotionEvent.ACTION_DOWN -> {
	//사용자가 화면에 처음으로 손가락을 댄 상태입니다.
}
MotionEvent.ACTION_MOVE -> {
	//사용자가 손가락을 화면 위에서 움직이고 있는 상태입니다.
}
MotionEvent.ACTION_UP -> {
	//사용자가 손가락을 화면에서 뗀 상태입니다
}
MotionEvent.ACTION_CANCEL -> {
	// 터치 이벤트가 취소된 상태입니다.
}

터치로 Drag&Drop 구현하기

간단한 프로젝트로 예를 들어 어떠한 뷰를 Drag&Drop을 통해 정답을 맞추는 퀴즈를 푼다고 하고 정답이 아니라면 원래 위치로 뷰를 위치시킨다고 해보는 코드를 작성해보겠습니다..

그러기 위해서는 터치 이벤트가 발생한 처음 좌표를 기억해야 합니다.

 imgDragX.setOnTouchListener{ view, event ->
            when(event.actionMasked){
                MotionEvent.ACTION_DOWN -> {
                    //터치 시작 위치 저장
                    initialX = view.x //초기 x좌표
                    initialY = view.y //초기 y좌표
                    dX = view.x - event.rawX //이전 X 좌표와 현재 터치 이벤트의 rawX 좌표를 비교하여 X 축으로 이동한 거리
                    dY = view.y - event.rawY //이전 Y 좌표와 현재 터치 이벤트의 rawY 좌표를 비교하여 Y 축으로 이동한 거리
                    Log.d("status", "ACTION_DOWN at X: ${event.rawX}, Y: ${event.rawY}") //초기 이벤트가 발생햇을 때의 x좌표, y좌표
                }
}

초기 좌표를 기억해 언제든지 돌아올 수 있는 좌푯값을 기억해 논 상태입니다.

이제 손가락으로 뷰를 움직이는 코드를 작성해보겟습니다.

 MotionEvent.ACTION_MOVE -> {
                    //새로운 좌표 계산 및 화면 범위 확인
                    val newX : Float = event.rawX + dX // 이전에 저장한 dx 값을 사용하여 현재 터치 이벤트의 rawX좌표와 더해 새로운 X 좌표를 계산합니다.
                    val newY : Float = event.rawY + dY // 이전에 저장한 dy 값을 사용하여 현재 터치 이벤트의 rawY좌표와 더해 새로운 Y 좌표를 계산합니다.
                    if(newX >= 0 && newY >= 0 && newX + view.width <= screenWidth && newY + view.height <= screenHeight) { //새로운 좌표 newX와 newY가 화면 범위 내에 있는지 확인합니다. 
                    newX와 newY가 모두 0 이상이며,newX + View의 너비가 화면의 가로 길이를 넘지 않고,
                    newY + View의 높이가 화면의 세로 길이를 넘지 않는지 검사합니다.
                        view.animate() //만약 새로운 좌표 newX와 newY가 화면 범위 내에 있는 경우, View를 해당 좌표로 애니메이션화하여 이동시킵니다
                            .x(newX)
                            .y(newY)
                            .setDuration(0)
                            .start()
                    }
                }

이 코드를 통해 터치 이벤트가 발생한 순간부터 이동할 때마다 새로운 좌표를 계산하고 이동한 좌표가 범위 내에 있는경우 View를 해당 좌표로 애니메이션화 하여 이동시킵니다(Drag)

이제 드래그 기능을 작성햇으니 Drop 기능을 작성하면 됩니다.
드랍 기능은 ACTION_UP을 통해 손가락을 떼면 뷰를 놓아지게 햇습니다.

 MotionEvent.ACTION_UP -> {
                    //정답 범위에 겹치는지 확인
                    val rectAnswer = Rect()
                    binding.imgLastAnswer.getGlobalVisibleRect(rectAnswer)
                    val rectView = Rect()
                    view.getGlobalVisibleRect(rectView)
                    if(Rect.intersects(rectAnswer, rectView)) {
                        //정답 범위에 들어왓을 시
                        }

이제 정답 밖의 범위에 Drop햇을시 초기 위치로 이동시켜주는 else문을 작성하면 끝입니다.

else {
                        //정답 범위와 겹치지 않앗을 때
                        view.animate()
                            .x(initialX)
                            .y(initialY)
                            .setDuration(0)
                            .start()

이렇게 작성하면 터치이벤트를 활용해 Drag&Drop 리스너 없이도 기능을 구현할 수 있습니다.

profile
개린이

0개의 댓글