다음은보기를 클릭 한 후 이벤트가 통과 한 예입니다.
먼저보기에서 DispatchTouchevent () 메소드를 분석하는데, 이는보기를 클릭하여 실행하는 첫 번째 방법입니다.
public boolean dispatchtouchevent (MotionEvent 이벤트) {if (montouchlistener! = null && (mviewflags & enabled_mask) == enabled && montouchlistener.ontouch (this, event)) {return true; } return ontouchevent (이벤트);}참고 : 두 개의 콜백 함수 ontouch () 및 ontouchevent (); 컨트롤이 OntouchListener에 바인딩되고 컨트롤이 활성화되면 ontouch () 메소드를 실행하십시오. 메소드가 True를 반환하면 Touch 이벤트가 Ontouchlistener 리스너에 의해 소비되었으며 아래쪽으로 분포되지 않음을 의미합니다. 그러나 허위 반환이 있으면 소비되지 않았으며 처리 제어의 ontouchevent ()로 계속 배포된다는 것을 의미합니다.
그런 다음 ontouchevent () 메소드를 분석하고 추가 터치 이벤트 처리를 수행하십시오.
if ((((viewflags & clickable) == 클릭 가능 || (ViewFlags & long_clickable) == long_clickable)) {switch (event.getAction ()) {case motionEvent.action_up : ..... performClick (); // 클릭 이벤트 브레이크에 응답합니다. Case MotionEvent.action_down : .... Break; Case MotionEvent.action_cancel : .... Break; Case MotionEvent.action_move : ..... Break; } true를 반환합니다. } false를 반환합니다.컨트롤이 클릭 가능하거나 long_clickable이면 해당 이벤트에 응답하고 응답이 완료된 후에는 응답을 계속할 수 있습니다. 예를 들어, 이벤트를 클릭하고, 먼저 Action_Down에 응답 한 다음, 깨지고 True를 반환 한 다음 손을 들어 DispatchTouchevent ()에서 배포 한 다음 Action_up에 응답 한 다음 PerformClick ()가 클릭 이벤트에 응답합니다.
클릭 이벤트에 응답합니다
public boolean performClick () {sendAccessibilityEvent (accessibilityEvent.type_view_clicked); if (monclicklistener! = null) {playsoundeffect (soundeffectConstants.click); monclicklistener.onclick (this); 진실을 반환하십시오. } return false;}monclicklistener.onclick (this)을 실행하십시오. 즉, 리스너를 바인딩하는 onclick () 함수입니다.
핵심 사항 :
Ontouch와 Ontouchevent의 차이점을 사용하는 방법은 무엇입니까?
답변:
View Control이 터치 이벤트를 수신하면 컨트롤이 OntouchListener 리스너에 바인딩되고 컨트롤이 활성화되면 Ontouch () 메소드를 실행하십시오. 사실이라면 터치 이벤트가 소비되었으며 더 이상 전달되지 않습니다. False가 반환되면 ontouchevent () 이벤트를 계속 호출하십시오.
Android 터치 이벤트가 활동 상단의 DecorView (Framelayout)로 전달되면보기 그룹을 통해 뷰 트리까지 레이어를 통해 레이어로 전달되며 마지막으로 이벤트를 실제 수신 뷰로 전달합니다. 다음은 몇 가지 중요한 방법입니다.
DispatchTouchevent
이벤트가 뷰 그룹에 전달되면 DispatchTouchevent가 호출됩니다. 코드가 삭제되었습니다
Public Boolean DispatchTouchevent (MotionEvent EV) {부울 핸들 = 거짓; if (onfiltertoucheventforsecurity (ev)) {최종 int action = ev.getaction (); 최종 int actionmasked = action & motionEvent.action_mask; //주의 1 : if (ActionMasked == motionevent.action_down) {cancelAndCleartouchTargets (EV); //이 메소드 resettouchState (); } //주의 2 : 마지막 부울을 가로 채어야하는지 확인하십시오. // 방금 눌렀거나 자식을 눌렀거나 자식을 처리 할 경우 (ActionMasked == MotionEvent.action_down || mfirsttouchtarget! = NULL) {최종 부울 비상 허구 간호 = (mgroupflags & flag_disallow_intercept)! = 0; if (! onallowintercept) {intercepted = onintercepttouchevent (ev); ev.setAction (action); // 변경된 경우 작업 복원} else {intercepted = false; }} else {// 액션 시퀀스의 시작이 아니며 처리 할 서브 뷰가 없습니다. 직접 인터셉트 = 참으로; } // 이벤트가 취소되지 않았으며 현재 뷰 그룹에서 가로 채지 않습니다. (! canceled &&! intercepted) {// 이것이 일련의 동작의 시작이거나 새로운 포인터 프레스가있는 경우 (actionMasked == motionEvent.Accion_Down || (split && ActionMasked == MointEvent.Action_Pointer_down)를 찾을 수있는 서브 뷰를 찾아야합니다. MotionEvent.action_hover_move) {최종 int actionIndex = ev.getActionIndex (); // DOWN의 경우 항상 0 0 // 터치 포인트의 위 제한 32는 최종 int idbitStoAssign = split을 유발한다는 것입니다. 1 << ev.getPointerId (ActionIndex) : touchTarget.all_pointer_ids; 최종 int childrencount = mchildrencount; if (newTouchTarget == null && childrencount! = 0) {final float x = ev.getx (ActionIndex); 최종 플로트 y = ev.gety (ActionIndex); // 현재 뷰 그룹의 모든 자식을 정렬하고 상단 층에 놓아 시작하십시오. 최종 ArrayList <View> preorderedList = buildOrderEdChildList (); 최종 부울 customorder = preorderedList == null && ischildrendrawingOrderEnabled (); 최종보기 [] 어린이 = MCHLDREN; for (int i = childrencount-1; i> = 0; i-) {Final int childindex = customorder? getChildDrawingOrder (ChildCount, i) : i; 최종보기 child = (preorderedList == null)? 어린이 [childindex] : preorderedList.get (childindex); // canviewReceivePointerEvents 가시보기가 이벤트를 수락 할 수 있습니다. // istransformedTouchpointInview (! canviewReceivePointerEvents (chield) ||! istransformedTouchpointInview (X, y, child, null)) {ev.setTargetAccessipus (오스일); 계속하다; } //이 포인터의보기가 이전 포인터를 처리했는지 여부를 처리 한 다음 NewTouchTarget = getTouchTarget (child)을 사용하십시오. if (newtouchtarget! = null) {// child는 이미 그 경계 내에서 터치를 받고 있습니다. // 처리중인 새로운 포인터 외에도 새로운 포인터를 제공합니다. newTouchTarget.pointerIdbits | = idbitstoAssign; 부서지다; }} //주의 3 : (DispatchTransformedTouchevent (EV, False, Child, IdbitStoAssign)) {// child는 그 경계 내에서 터치를 받기를 원합니다. mlastTouchdownTime = ev.getDownTime (); if (preorderedList! = null) {// childindex가 사소한 목록으로 가리키고 (int j = 0; j <childrencount; j ++) {if (children [childindex] == mchildren [j]) {mlasttouchdownIndex = j; 부서지다; }}} else {mlasttouchdownIndex = childindex; } mlasttouchdownx = ev.getx (); mlasttouchdowny = ev.gety (); newTouchTarget = addTouchTarget (child, idbitstoassign); 이미 dispatchedtonewtouchtarget = true; 부서지다; }}}}}}} // 이벤트를받는 어린이보기가 전에 발견되었습니다. 그것이 널이면, 그것은 어린이보기가 인수되지 않았 음을 의미합니다. 현재 뷰 그룹은 if (mfirsttouchtarget == null) {// viewGroup Handled = dispatchTransformedTouchevent (ev, cancelchild, null, touchtarget.all_pointer_ids)를 처리해야합니다. } else {if (이미 DispatchTransformedTouchevent (dispatchTransformedTouchevent (ev, cancelchild, target.child, target.pointeridbits)) {handled = true; }}} return handled;}위의 코드의 관심은 후반에 관련 될 것이므로주의를 기울이십시오.
여기서 일련의 행동에서 다른 포인터가 다른 관점에 할당 될 수 있음을 지적해야합니다. ViewGroup은 뷰를 처리하는 포종 및 터치 타겟 목록을 유지합니다. TouchTarget은 포인터를 처리 할 수있는 서브 뷰를 나타냅니다. 물론, 뷰는 두 손가락이 하위 뷰 영역에있는 것과 같은 여러 포인터를 처리 할 수 있습니다. TouchTarget은 내부적으로 INT를 사용하여 처리 할 수있는 포인터 리드 및 INT32 비트를 저장하므로 상단 레이어는 동시에 최대 32 점의 터치 만 허용 할 수 있습니다.
주의 3에서 코드를 살펴 보겠습니다. 우리는 종종보기의 DispatchTouchevent가 False를 반환하면 동작을 뒤따를 수 없다고 말합니다. 이게 왜? False가주의 3에서 반환되면 TouchTarget에 기록되지 않기 때문에 ViewGroup 은이 이벤트를 처리 할 능력이 없다고 생각합니다.
ViewGroup이 실제로 DispatchTransformedTouchevent의 이벤트를 처리하고 팔로우하고 살펴 봅니다.
DispatchTransformedToucheventPrivate Boolean DispatchTransformedTouchevent (MotionEvent 이벤트, 부울 취소, 자식보기, int desiredPointerIdbits) {// 서브 클래스 처리 없음, (child == null) {handled = super.dispatchevent (transformevent); } else {Final Float Offsetx = mscrollx -child.mleft; 최종 플로트 오프셋 = MSCrolly -child.mtop; transformedEvent.OffSetLocation (offsetx, offsety); if (! child.hasidentitymatrix ()) {transformedEvent.Transform (child.getInversEmatrix ()); } handled = child.dispatchtouchevent (transformedEvent); } 반환 처리;}뷰의 DispatchTouchevent가 호출되는 것을 볼 수 있습니다. 이는 클릭 이벤트가 실제로 처리되는 곳입니다.
DispatchTouchevent Public Boolean DispatchTouchevent (MotionEvent 이벤트) {if (onfiltertoucheventforsecurity (event)) {// Ontouch가 True LeaterInfo li = mlistenerinfo를 반환하는 경우 views의 Ontouch 이벤트를 먼저 가져옵니다. if (li! = null && li.montouchlistener! = null && (mviewflags & enabled_mask) == enabled && li.montouchlistener.ontouch (this, event)) {result = true; } if (! result && ontouchevent (event)) {result = true; }} 반환 결과; }우리가보기를 위해 설정 한 Ontouch 이벤트는 우선 순위가 높습니다. Ontouch 실행이 true를 반환하면보기의 ontouchevent가보기로 이동하지 않습니다. 클릭 이벤트 중 일부는 Ontouchevent에서 처리되므로 Ontouch가 True를 반환하고 View의 클릭 관련 이벤트가 처리되지 않습니다.
이 과정에 대한 간단한 요약
ViewGroup이 Superiors가 전달한 이벤트를 수락 할 때, 일련의 T 현재 클릭중인보기를 찾아 대상보기의 DispatchTouchevent를 즉시 호출하십시오. 대상보기의 DispatchTouchevent가 False를 반환하면 대상보기가 해당 위치에만 있다고 생각합니다. 이 행사를 받아들이고 싶지는 않지만 조용히보기를 원합니다 (조용히 당신이 척하는 것을 봅니다). 현재 ViewGroup은 DispatchTouchevent로 이동하여 완료됩니다!