티스토리 뷰

터치이벤트의 종류

다운 이벤트, 이동 이벤트, 업 이벤트 -> 순서대로 동작하며, 이동이벤트는 생략될수 있다. 

디바이스의 터치 정보는 시스템 서비스인 윈도우 매니저에 전달이 되고, 윈도우 매니저는 화면에 떠있는 앱에 최종 전달한다.

터치이벤트 함수

앱에서 터치 이벤트는 최초 액티비티를 통해 최초 전달되며, 액티비티의 두함수를 재정의하여 컨트롤 할수있다. 정의하지 않으면 화면에 배치된 각종 뷰에 순차적으로 전달 된다.

dispatchTouchEvent
onTouchEvent

화면터치하면 먼저 dispatchTouchEvent 가 호출되고, 이어서 onTouchEvent 가 호출이 된다

이벤트의 정보에는 getX( 이벤트가 발생한 x축 위치 ), getY, getAction, getDownTime( down 이벤트가 발생한 시간 millis ), 등이 표시된다.

이벤트는 가장 최산단의 뷰( 액티비티 )부터 아례로 계층구조로 전달된다.

터치이벤트의 전달과정

최상단의 뷰에서 가장먼저 dispatchTouchEvent 가 발생하고, 그다음 하위뷰의 dispatchTouchEvent 가 발생한다. 제일 하위단의 자식뷰에서 dispatchTouchEvent 가 발생되면 onTouchEvent가 연쇄적으로 발생하며 이때 이벤트를 사용할거면 true 를 리턴시키면된다. 최하위의 onTouchEvent 에서 false 를 리턴하게 되면 dispatchTouchEvent 는 false 를 리턴하게되며 상위단으로 넘어간다. 이때 다시 onTouchEvent가 상위 뷰에서 발생하며 위 내용을 반복하여 호출한다. onTouchEvent 에서 true 를 리턴하게 되면 dispatchTouchEvent 도 true 를 리턴하게 되고 이떄는 onTouchEvent가 발생하지 않는다.

이렇게 이벤트의 흐름이 있고, dispatchTouchEvent 와 onTouchEvent 가 두개있는 이유이다.

dispatchTouchEvent 는 단지 뷰를 탐색해 나가는 기능을 위한 함수이고, 이 이벤트를 받아서 처리를 하려면 onTouchEvent를 재정의하여 처리하도록 한다.

onIterceptTouchEvent 함수

onIterceptTouchEvent 함수는 자식 뷰로 전달되는 터치 이벤트를 부모 뷰그룹이 가로챌 수 있게 한다. 무작정 가로챈다면 쓸수 있는 자식뷰가 하나도 없을것이다.. 따라서 자신에게 필요한 이벤트라 판단되면 가로챈다. 또한 이벤트를 가로채게 되면 자식뷰에서는 ACTION_CANCEL 이라는 액션을 onTouchEvent 를 통해 전달해준다.

보통 터치다운의 위치에서 20픽셀 이상 이동되면 이벤트를 가로채서 onIterceptTouchEvent 에 리턴값을 true 로 한다.

requestDisallowInterceptTouchEvent 함수

이 함수는 자식 뷰가 부모 뷰그룹에게 이벤트를 가로채지 않도록 요청한다. 매개변수로 true 를 넘겨주면된다. 단, 한번의 터치 프로세스에만 유효하다.

Some devices can report multiple movement traces at the same time. Multi-touch screens emit one movement trace for each finger. The individual fingers or other objects that generate movement traces are referred to as pointers. Motion events contain information about all of the pointers that are currently active even if some of them have not moved since the last event was delivered.

The number of pointers only ever changes by one as individual pointers go up and down, except when the gesture is canceled.

Each pointer has a unique id that is assigned when it first goes down (indicated by ACTION_DOWN or ACTION_POINTER_DOWN). A pointer id remains valid until the pointer eventually goes up (indicated by ACTION_UP or ACTION_POINTER_UP) or when the gesture is canceled (indicated by ACTION_CANCEL).

The MotionEvent class provides many methods to query the position and other properties of pointers, such as getX(int), getY(int), getAxisValue(int), getPointerId(int), getToolType(int), and many others. Most of these methods accept the pointer index as a parameter rather than the pointer id. The pointer index of each pointer in the event ranges from 0 to one less than the value returned by getPointerCount().

The order in which individual pointers appear within a motion event is undefined. Thus the pointer index of a pointer can change from one event to the next but the pointer id of a pointer is guaranteed to remain constant as long as the pointer remains active. Use the getPointerId(int) method to obtain the pointer id of a pointer to track it across all subsequent motion events in a gesture. Then for successive motion events, use the findPointerIndex(int) method to obtain the pointer index for a given pointer id in that motion event.

허접한 영어 실력으로 대충 요약을 해보자면, 터치를 했을때 onTouchEvent 콜백 메서드로 전달되는 MotionEvent속에 pointer라는것이 존재하는데 이 포인터는 여태까지 터치된 곳의 정보를 담고 있는 어떤 객체이며 인덱스와 아이디를 갖는다. 인덱스는 변경 될 수 있지만 아이디는 변경되지 않는다. 

성능 개선된 페인트 보드 DrawingView.java

현재 업데이트된 부분만 다시 그리는 페인트 보드를 만들기 위한 코드가 바로 위에 있는 코드이다.

이 코드에서는 dirty된 부분만 다시 그리기 위해서 dirtyRect라는것을 사용한다.

다운 모션과 업 모션 사이에서 무브 모션이 일어나는데, 이때 만약에 다운 모션과 업 모션 사이의 시간이 무브 이벤트가 앱에 전달되는 시간 보다 더빠르다면, 그 스킵된 이벤트들은 MotionEvent객체 내의 History로 저장된다. 따라서 그 스킵된 좌표들을 HistoricalX 메서드로 가져올수 있다.

위의 코드를 보면 스킵된 히스토리 X,Y좌표를 path객체에 add하고 있는 모습을 볼 수 있다. 나중에 onDraw메서드에서 canvas.drawPath(path,paint)를 하게 되는데 이때 저장된 path를 그리게 된다.

invalidate();를 호출하게 되면 onDraw()가 재 호출 되게 되는데 이때 invalidate의 매개변수로 dirtyRect의 상,하,좌,우 좌표 4개를 전달하고 있다. 따라서, onDraw()속에서 drawPath()를 하게 될때 패스는 그려야할 모든 패스가 다 저장되어 있지만, 실제로 다시 그리는것은 이 dirtyRect가 차지하는 부분만 다시 그리게 된다.

그렇기 때문에 모든 패스를 invalidate할때마다 다시 그려야 하는 다른 페인트 보드 앱 보다 더 속도를 빠르게 구현 할 수 있다.



출처

https://moka-a.github.io/android/touch-event-transfer/

https://developer.android.com/reference/android/view/MotionEvent.html#getHistorySize()

http://opencarts.org/sachlaptrinh/pdf/27535.pdf : Android CookBook.pdf 241페이지 -> 성능 개선 페인트 보드 코드

'컴퓨터 공학과 졸업 > 안드 개발 기록' 카테고리의 다른 글

File, File Path, SharedPreferences  (0) 2018.07.21
암시적인텐트  (0) 2018.07.21
AppBarLayout  (0) 2018.07.14
MVP패턴  (0) 2018.07.13
뷰페이저  (0) 2018.07.13
댓글
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함