2022년 1월 21일 금요일

[요약] Android Touch System — Part 1: Touch Functions and the View Hierarchy

https://proandroiddev.com/android-touch-system-part-1-touch-functions-and-the-view-hierarchy-1f6526e55d78

Android Touch System — Part 1: Touch Functions and the View Hierarchy


터치 스크린상에서의 모든 움직임은 MotionEvent로 알려진다.

MotionEvent는 다음의 값들을 가진다.

action : 수행한 action의 타입
x : 터치한 x좌표, view에 상대적인 위치
y : 터치한 y좌표,  view에 상대적인 위치
rawX : 터치한 절대 x좌표, 디바이스 화면에 상대적인 위치
rawY : 터치한 절대 y좌표, 디바이스 화면에 상대적인 위치
eventTime : 이벤트가 발생한 시간, SystemClock.uptimeMilllis()

안드로이드 화면은 좌상단이 (0, 0)이고 우하단이 (maxX, maxY)이다.

action은 다음의 값을 가진다.


ACTION_DOWN : 터치가 처음으로 일어났을 때
ACTION_UP : 터치를 화면에서 떼었을 때
ACTION_MOVE : ACTION_DOWN과 ACTION_UP 사이에 터치가 이동할 때
ACTION_CANCEL : 현재 터치가 취소될 때. parent view가 child view의 이벤트를 인터셉트할 때 발생한다.

이벤트의 흐름


motion event가 발생하면 root view(예: Activity)로부터 중간에 인터셉트당하지 않으면 가장 하위의 view까지 내려간다. 내려갈 때, view의 dispatchTouchEvent()가 호출된다. 여기 안에서 onInterceptTouchEvent()가 호출되는데 false를 리턴하면 아래로 계속 내려가지만 true를 리턴하면 더이상 아래로 내려가지 않는다.(이벤트는 여기서 소비된다.) 이벤트가 leaf view까지 내려가거나 onInterceptTouchEvent()가 true를 리턴해서 더이상 아래로 내려가지 않으면 다시 위로 올라가면서 onTouchEvent()가 호출된다. onTouchEvent()가 true를 리턴하면 이벤트는 여기서 멈춘다.

dispatchTouchEvent()

View.dispatchTouchEvent : view는 children을 갖지 않는다. 따라서, 구현은 간단하다. onTouchEvent()를 호출하고, touch listener를 view에 설정한다. 이 리스너중 하나라도 true를 리턴하면 true를 리턴한다.
custom view는 dispatchTouchEvent 보다는 onTouchEvent를 override 하는 것이 좋다.

ViewGroup.dispatchTouchEvent : onInterceptTouchEvent()를 호출한다. 여기서 false를 리턴하면 추가된 반대의 순서로 child view들을 순회한다. 이중 터치가 child view의 안에서 발생한 것이면 child.dispatchTouchEvent()를 호출한다. 여기서 false를 리턴하면 다음 child에서 child.dispatchTouchEvent()를 호출한다.
ViewGroup은 dispatchTouchEvent 보다는 onInterceptTouchEvent를 override 하는 것이 좋다.

ScrollView.dispatchTouchEvent : ViewGroup과 같다.

Activity.dispatchTouchEvent : 자식들의 dispatchTouchEvent()를 호출한다. 

onInterceptTouchEvent()


View.onInterceptTouchEvent : 없다.

ViewGroup.onInterceptTouchEvent : 기본 구현은 false를 리턴한다. 이 함수를 override 하는 주 목적은 특정한 타입의 터치 이벤트만 다루고 나머지는 자식들이 다루도록 하기 위함이다. 예를 들어 ScrollView는 스크롤은 직접 다루고, 클릭 같은 것은 자식이 다루도록 한다.

ScrollView.onIntreceptTouchEvent : 이벤트가 ACTION_MOVE이고, velocity가 충분하면 true를 리ㅣ턴한다. 그리고 자식들은 ACTION_CANCELLEDD를 받게 된다. 또한 requestDisallowInterceptTouchEvent를 호출한다.

Activity.onInterceptTouchEvent : 없다.

onTouchEvent()


View.onTouchEvent : view가 clickable 하면 기본은 true를 리턴한다. overriding할거면 super.onTouchEvent()를 호출해주는 것이 좋다. 또는 click gesture만 다룰거라면 performClick()를 override하는 것이 좋다.

ViewGroup.onTouchEvent : View의 onTouchEvent와 같다.

ScrollView.onTouchEvent : event의 정보를 통해 얼마나 스크롤했는지를 알아내서 스크롤을 수행한다. 스크롤과 관련된 애니메이션도 다룬다. 또한 requestDisallowInterceptTouchEvent()를 호출한다.

Activity.onTouchEventv : 기본 구현은 항상 false를 리턴한다.

requestDisallowInterceptTouchEvent()

ViewParent 인터페이스의 함수. parent나 ancestor view가 터치 이벤트를 인터셉트하지 못하도록 할 때 사용한다.

Building asynchronous views in SwiftUI 정리

Handling loading states within SwiftUI views self loading views View model 사용하기 Combine을 사용한 AnyPublisher Making SwiftUI views refreshable r...