TOUCH EVNET FLOW
Activity 를 하나 상속받아서 view 를 하나 만들었다고 하자. 이 때 그 view 위에서 touch 를 하게 되면 아래와 같은 경로로 event 가 전달된다.말로 설명을 하자면, activity의 dispatchTouchEvent() 가 호출되면서 window 의 superDispatchTouchEvent(ev) 를 호출한다. 이 superDispatchTouchEvent() 가 최상위에 있는 Dispatch 해주는 녀석이라고 봐도 무방할 듯 하다. 아무튼 이 녀석으로부터 시작해서 child 의 dispatchTouchEvent(event) 를 호출하고, 그 child 의 child 의 dispatchTouchEvent(event)를 호출하고, 또 그 child의 child 의 child 의 dispatchTouchEvent(event)를 호출한다. 이런 식으로 쭉 밑으로 내려 가다보면, View 의 dispatchTouchEvent(event) 로 가게 되고, 여기서 최종적으로 View 의 OnTouchEvent() 를 호출하게 된다.
하지만 참고로 Window 가 가장 밑에 있는 녀석을 이야기 하는 것이다. 가장 마지막의 child 가 가장 상위의 widget 이 되는 것이다.
ViewFlowExample(Activity).dispatchTouchEvent() public boolean dispatchTouchEvent(MotionEvent ev) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { onUserInteraction(); } if (getWindow().superDispatchTouchEvent(ev)) { return true; } return onTouchEvent(ev); }
getWindow().superDispatchTouchEvent(ev) --> PhoneWindow$DecorView(ViewGroup).dispatchTouchEvent PhoneWindow$DecorView(ViewGroup).dispatchTouchEvent(MotionEvent) intercepted = onInterceptTouchEvent(ev); if (!canceled && !intercepted) if (actionMasked == MotionEvent.ACTION_DOWN || (split && actionMasked == MotionEvent.ACTION_POINTER_DOWN) || actionMasked == MotionEvent.ACTION_HOVER_MOVE) if (childrenCount != 0) for (int i = childrenCount - 1; i >= 0; i--) dispatchTransformedTouchEvent() handled = child.dispatchTouchEvent(event); return handled; child.dispatchTouchEvent(event); ---> LinearLayout(ViewGroup).dispatchTouchEvent() LinearLayout(ViewGroup).dispatchTouchEvent() intercepted = onInterceptTouchEvent(ev); if (!canceled && !intercepted) dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign) handled = child.dispatchTouchEvent(event); FrameLayout(ViewGroup).dispatchTouchEvent() intercepted = onInterceptTouchEvent(ev); if (!canceled && !intercepted) dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign) handled = child.dispatchTouchEvent(event); LinearLayout(ViewGroup).dispatchTouchEvent() intercepted = onInterceptTouchEvent(ev); if (!canceled && !intercepted) dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign) handled = child.dispatchTouchEvent(event); ViewFlow(ViewGroup).dispatchTouchEvent() intercepted = onInterceptTouchEvent(ev); if (!canceled && !intercepted) dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign) handled = child.dispatchTouchEvent(event); LinearLayout(ViewGroup).dispatchTouchEvent() intercepted = onInterceptTouchEvent(ev); if (!canceled && !intercepted) dispatchTransformedTouchEvent(ev, false, child, idBitsToAssign) handled = child.dispatchTouchEvent(event);
// i don't know why the below routine is travered. TextView(View).dispatchTouchEvent() TextView.onTouchEvent() super.onTouchEvent() if (mFirstTouchTarget == null) handled = dispatchTransformedTouchEvent(ev, canceled, child=null, TouchTarget.ALL_POINTER_IDS); { if (newPointerIdBits == oldPointerIdBits) if (child == null || child.hasIdentityMatrix()) if (child == null) handled = super.dispatchTouchEvent(event);
TextView(View).dispatchTouchEvent() { if(li.mOnTouchListener.onTouch(this, event) ...) // OnTouchListener which is bined to the view. return true View.onTouchEvent(event)
} return handled } if (mFirstTouchTarget == null) handled = dispatchTransformedTouchEvent(ev, canceled, null, TouchTarget.ALL_POINTER_IDS);
이것을 정리하면 아래와 같다.
Activity.dispatchTouchEvent() ViewGroup.dispatchTouchEvent() ViewGroup.onInterceptTouchEvent() View.dispatchTouchEvent() View.onTouch() View.onTouchEvent() ViewGroup.onTouch() ViewGroup.onTouchEvent() Activity.onTouchEvent()
ViewGroup.onInterceptTouchEvent() 를 시작으로,
--> View.onTouch()
--> View.onTouchEvent()
--> ViewGroup.onTouch()
--> ViewGroup.onTouchEvent()
의 순서대로 event 가 전달된다고 할 수 있다.
Event 는 Action_Down 이 어디에서 return 이 되었느냐에 따라 그 이후의 event 인 Action_Move, Action_Up 을 전달 해 준다. 이것은 [ref. 1] 의 그림을 참조하는 것이 좋을 듯 하다.
ViewGroup.OnInterceptTouchEvent() 의 의미만 명확히 해 두면 나머지는 파악하기 쉬울 듯 하다.
ViewGroup.OnInterceptTouchEvent() 를 return true 로 한다는 뜻은 Action_Down event 를 intercepted 했다는 이야기이다. 하지만 이 intercept 가 ViewGoup 의 child 인 다른 ViewGroup 이나 View 에게로 Action_Down event 를 주지 않는다는 이야기이지, 자신(ViewGroup) 의 onTouchEvent() 나 onTouch() 로 주지 않겠다는 이야기는 아니다.
그러므로 ViewGroup.onInterceptTouchEvent() 에서 return true 가 되면, View.diapatchTouchEvent() 를 거치지는 않지만, 그 다음 routine 인 ViewGroup.onTouch() 나 ViewGroup.onTouchEvent() 는 실행이 된다.
여하튼 내가 정리해도, 정리가 잘 안되는 느낌이다. ^^;;; 그래서 다른 책(Pro Android 4)의 내용을 참고해서 얘기를 해준다면, event 를 사용하고 다른 view 나 child 에게 넘기지 않으려 한다면 return true 를 하고, 다른 view 나 child 에서 사용을 해야 한다면 return false 를 하라고 한다.
ONTOUCH() VS ONTOUCHEVENT()
두 개는 사실상 비슷한 녀석으로 보인다. 굳이 나눠놓은 이유를 아직 잘 모르겠지만, 구현방식은 아래와 같다.onTouch()
onTouch() 는 setOnTouchListener() 등을 통해서 View 에 binding 시켜주면 되고,
listView.setOnTouchListener(new OnTouchListener(){ @Override public boolean onTouch(View v, MotionEvent event) { // TODO Auto-generated method stub android.util.Log.d("test", "onTouch"); return false; } });
onTouchEvent()
onTouchEvent() 는 View 를 상속한 class 에서 onTouchEvent() 함수를 override 해주면 된다.public class ViewFlow extends AdapterView<Adapter>{ @Override public boolean onTouchEvent(MotionEvent ev) { ... switch (action) { case MotionEvent.ACTION_DOWN: ... break; case MotionEvent.ACTION_MOVE: f... break; } return true; } }
출처 - [컴][안드로이드] onTouch() 와 onTouchEvent() 가 호출되는 순서
'Programming > Android' 카테고리의 다른 글
GestureDetector 2 (0) | 2013.06.28 |
---|---|
안드로이드의 Touch Event 디스패치 단계 (0) | 2013.01.31 |
BluetoothSocket의 연결 오류 (2) | 2012.08.24 |
갑자기 발생하는 java.lang.NoClassDefFoundError 에 대한 대책 (0) | 2012.05.03 |
이클립스 - 안드로이드 프레임워크 소스 보기(for Windows) (0) | 2012.04.09 |