ต่อไปนี้เป็นตัวอย่างของเหตุการณ์ที่ผ่านหลังจากคลิกที่มุมมอง
ขั้นแรกให้วิเคราะห์เมธอด dispatchTouchEvent () ในมุมมองซึ่งเป็นวิธีแรกในการดำเนินการโดยคลิกที่มุมมอง
Public Boolean DispatchTouchEvent (เหตุการณ์ MotionEvent) {ถ้า (montouchListener! = null && (mViewFlags & enabled_mask) == เปิดใช้งาน && montouchListener.ontouch (เหตุการณ์นี้)) {return true; } return ontouchEvent (เหตุการณ์);}หมายเหตุ: มันมีฟังก์ชั่นการโทรกลับสองฟังก์ชั่น OnTouch () และ OnTouchEvent (); หากการควบคุมถูกผูกไว้กับ ontouchListener และเปิดใช้งานการควบคุมให้ดำเนินการวิธี ontouch () หากวิธีการส่งคืนจริงก็หมายความว่าเหตุการณ์สัมผัสได้ถูกใช้โดยผู้ฟัง ontouchListener และจะไม่ถูกแจกจ่ายลง แต่ถ้าผลตอบแทนที่ผิดพลาดก็หมายความว่ามันยังไม่ได้ถูกบริโภคและยังคงแจกจ่ายลงไปยัง OnTouchEvent () ของการควบคุมการประมวลผล
จากนั้นวิเคราะห์วิธี OnTouchEvent () และดำเนินการประมวลผลเหตุการณ์แบบสัมผัสเพิ่มเติม
if (((viewflags & clickable) == 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; } return true; } return false;หากการควบคุมสามารถคลิกได้หรือ long_clickable ก็สามารถตอบสนองต่อเหตุการณ์ที่เกี่ยวข้องและส่งคืนจริงหลังจากการตอบกลับเสร็จสิ้นเพื่อดำเนินการตอบกลับ ตัวอย่างเช่นเมื่อคลิกเหตุการณ์ก่อนที่จะตอบสนองต่อ action_down จากนั้นทำลายและส่งคืนจริงจากนั้นยกมือของคุณจากนั้นแจกจ่ายจาก dispatchTouchEvent () จากนั้นตอบสนองต่อ Action_up และ PerformClick () จะตอบสนองต่อเหตุการณ์คลิก
ตอบสนองต่อเหตุการณ์คลิก
Public Boolean PerformClick () {SendAccessibilityEvent (accessibleEvent.type_view_clicked); if (monclicklistener! = null) {playsoundeffect (soundeffectconstants.lick); monclicklistener.onclick (นี่); กลับมาจริง; } return false;}ดำเนินการ monclicklistener.onclick (นี่); นั่นคือฟังก์ชั่น onclick () ที่ผูกมัดผู้ฟัง
ประเด็นสำคัญ:
จะใช้ความแตกต่างระหว่าง OnTouch และ OnTouchEvent ได้อย่างไร?
คำตอบ:
เมื่อ View Control ได้รับเหตุการณ์การสัมผัสหากการควบคุมถูกผูกไว้กับผู้ฟัง ontouchListener และเปิดใช้งานการควบคุมให้ดำเนินการวิธี ontouch () หากเป็นจริงเหตุการณ์การสัมผัสได้ถูกใช้ไปแล้วและจะไม่ถูกส่งต่อไปอีกต่อไป หากส่งคืนเท็จให้โทรหาเหตุการณ์ OnTouchEvent () ต่อไป
หลังจากเหตุการณ์ Android Touch ถูกส่งผ่านไปยัง Decorview (framelayout) ที่ด้านบนของกิจกรรมมันจะถูกส่งผ่านเลเยอร์ผ่านเลเยอร์ผ่านมุมมองไปยังทรีวิวและในที่สุดก็ส่งเหตุการณ์ไปยังมุมมองที่ได้รับจริง นี่คือวิธีการสำคัญบางอย่าง
dispatchTouchEvent
เมื่อเหตุการณ์ถูกส่งผ่านไปยัง ViewGroup จะมีการเรียก DispatchTouchEvent รหัสถูกลบ
บูลีนสาธารณะ DispatchTouchEvent (MotionEvent EV) {บูลีนจัดการ = false; if (onfilterTouchEventForSecurity (eV)) {การกระทำ int สุดท้าย = eV.getAction (); int final actionMasked = action & motionEvent.Action_mask; // ความสนใจ 1: ล้างบางรัฐเมื่อกดถ้า (actionMasked == motionEvent.Action_down) {CancelandCleartouchTargets (eV); // หมายเหตุวิธีนี้ ResettouchState (); } // ความสนใจ 2: ตรวจสอบว่าบูลีนสุดท้ายที่สกัดกั้นจะต้องถูกดักจับหรือไม่ // ถ้าคุณเพิ่งกดหรือมีมุมมองเด็กเพื่อจัดการกับมันถ้า (actionMasked == motionEvent.action_down || mfirsttouchtarget! = null) {บูลีนสุดท้าย disallowintercept = (mGroupflags & flag_disallow_intercept)! = 0; if (! disallowIntercept) {intercepted = OnInterceptTouchEvent (eV); ev.setAction (การกระทำ); // คืนค่าการดำเนินการในกรณีที่มีการเปลี่ยนแปลง} else {intercepted = false; }} else {// ไม่ใช่จุดเริ่มต้นของลำดับการกระทำและไม่มีมุมมองย่อยที่จะจัดการ สกัดกั้นโดยตรง = จริง; } // เหตุการณ์ไม่ได้ถูกยกเลิกและไม่ได้ถูกดักจับโดย ViewGroup ปัจจุบัน ไปดูว่ามีมุมมองย่อยที่ถูกครอบครองหรือไม่หาก (! ยกเลิก &&! intercepted) {// ถ้านี่คือจุดเริ่มต้นของชุดของการกระทำหรือมีตัวชี้ใหม่ที่กดเราต้องหาวิวทิวทัศน์ที่สามารถจัดการตัวชี้นี้ได้หาก (actionmasked == motion MotionEvent.Action_Hover_Move) {ขั้นสุดท้าย int actionIndex = eV.getActionIndex (); // เสมอ 0 สำหรับการลง // ข้อ จำกัด ด้านบนของจุดสัมผัส 32 คือมันทำให้เกิด int Idbitstoassign สุดท้าย = แยก? 1 << ev.getPointerid (ActionIndex): touchTarget.all_pointer_ids; int childrencount สุดท้าย = mchildrencount; if (newTouchTarget == null && childRencount! = 0) {float สุดท้าย x = ev.getx (actionIndex); Final Float y = ev.gety (ActionIndex); // เรียงลำดับเด็กทั้งหมดของ ViewGroup ปัจจุบันและวางไว้ในชั้นบนเพื่อเริ่มต้น arrayList สุดท้าย <ดู> preorteredList = buildOrderEdChildList (); Boolean Final CustomERDERNER = PreorterEdList == NULL && ISCHILDRENDRAWINGENDENABLEDENABLED (); มุมมองสุดท้าย [] เด็ก = mchildren; สำหรับ (int i = childRencount-1; i> = 0; i--) {final int childIndex = custom order? getChildDrawingOrder (childCount, i): i; Final View Child = (preorteredList == null)? เด็ก ๆ [ChildIndex]: PreorderedList.get (ChildIndex); // CanViewReceivePoInterevents มุมมองที่มองเห็นได้สามารถยอมรับเหตุการณ์ // iTransformedTouchPointInview คำนวณว่ามันจะตกอยู่ในพื้นที่คลิกหรือไม่ถ้า (! ดำเนินการต่อ; } // สามารถจัดการได้ว่ามุมมองของตัวชี้นี้ได้ประมวลผลตัวชี้ก่อนหน้านี้หรือไม่จากนั้นใช้ newTouchTarget = getTouchTarget (เด็ก); ถ้า (newTouchTarget! = null) {// เด็กได้รับการสัมผัสภายในขอบเขตแล้ว // ให้ตัวชี้ใหม่นอกเหนือจากที่มันกำลังจัดการ newtouchtarget.pointeridbits | = idbitstoassign; หยุดพัก; }} // ความสนใจ 3: ส่งโดยตรงไปยังมุมมองเด็กถ้า (dispatchTransformedTouchEvent (ev, false, child, idbitstoassign)) {// เด็กต้องการรับสัมผัสภายในขอบเขตของมัน mlasttouchdowntime = ev.getDowntime (); if (preorderedList! = null) {// childIndex ชี้ไปที่รายการ presorted, ค้นหาดัชนีต้นฉบับสำหรับ (int j = 0; j <childrencount; j ++) {ถ้า (เด็ก [childindex] == mchildren [j]) {mlasttouchdownindex = j; หยุดพัก; }}} else {mlastTouchDownIndex = childIndex; } mlasttouchdownx = ev.getx (); mlasttouchdowny = ev.gety (); newTouchTarget = addTouchTarget (เด็ก, idbitstoassign); adeDispatchedTonewTouchTarget = true; หยุดพัก; }}}}}} // มุมมองเด็กที่ได้รับเหตุการณ์ก่อนหน้านี้ หากเป็นโมฆะก็หมายความว่าไม่มีการยึดครองเด็ก ViewGroup ปัจจุบันจำเป็นต้องจัดการ IF (MFIRSTTOUCHTARGET == NULL) {// ViewGroup HADLED = DISPATCHTRANSFORMEDTOUCHEVENT (EV, CANCELCHILD, NULL, TouchTarget.ALL_POINTER_IDS); } else {if (adeDispatchEdOnewTouchTarget) {// ละเว้นรหัสบางส่วนถ้า (dispatchTransformedTouchEvent (ev, cancelchild, target.child, target.pointeridbits)) {handled = true; }}} return handled;}ความสนใจในรหัสข้างต้นจะมีส่วนร่วมในส่วนต่อมาดังนั้นให้ความสนใจกับมัน
มันควรจะชี้ให้เห็นที่นี่ว่าพอยน์เตอร์ที่แตกต่างกันในชุดของการกระทำสามารถกำหนดให้กับมุมมองที่แตกต่างกันเพื่อตอบสนอง ViewGroup จะรักษา pointerid และรายการ touchTarget ที่จัดการกับมุมมอง TouchTarget แสดงถึงมุมมองย่อยที่สามารถจัดการพอยน์เตอร์ได้ แน่นอนมุมมองสามารถจัดการกับพอยน์เตอร์หลายตัวเช่นสองนิ้วอยู่ในพื้นที่ดูย่อย TouchTarget ใช้ int ภายในเพื่อจัดเก็บ pointerid ที่สามารถประมวลผลและบิต INT32 ซึ่งเป็นสาเหตุที่ชั้นบนสามารถอนุญาตให้แตะได้สูงสุด 32 คะแนนในเวลาเดียวกัน
ลองดูที่รหัสที่ความสนใจ 3 เรามักจะพูดว่าถ้า DispatchTouchEvent ของมุมมองกลับมาเป็นเท็จมันก็ไม่สามารถตามด้วยการกระทำได้ ทำไมถึงเป็นเช่นนี้? เพราะหากเท็จถูกส่งคืนที่ความสนใจ 3 มันจะไม่ถูกบันทึกไว้ใน TouchTarget ViewGroup เชื่อว่าคุณไม่มีความสามารถในการจัดการเหตุการณ์นี้
คุณสามารถดูได้ที่นี่ว่า ViewGroup จัดการเหตุการณ์ใน DispatchTransformedTouchEvent ติดตามและดู:
DispatchTransformedTouchEventPrivate บูลีน DispatchTransformedTouchEvent (เหตุการณ์ MotionEvent, Boolean ยกเลิก, ดูเด็ก, int ที่ต้องการ pointeridbits) {// ไม่มีการประมวลผล subclass จากนั้นปล่อยให้ ViewGroup สำหรับการประมวลผลหาก (เด็ก == null) } else {Final Float Offsetx = mscrollx - child.mleft; Final Float Offsety = mscrolly - child.mtop; TransformedEvent.OffSetLocation (OffsetX, Offsety); if (! child.hasidentityMatrix ()) {transformedEvent.transform (child.getInversematrix ()); } handled = child.dispatchTouchEvent (transformedEvent); } return handled;}คุณจะเห็นได้ว่าไม่ว่าจะมีการเรียกมุมมองที่เรียกว่าอะไรซึ่งเป็นที่ที่มีการจัดการเหตุการณ์การคลิกจริง ๆ
DispatchTouchEvent Public Boolean DispatchTouchEvent (Event MotionEvent) {ถ้า (onfilterTouchEventForSecurity (เหตุการณ์)) {// รับเหตุการณ์ ontouch ก่อนหน้า if (li! = null && li.montouchListener! = null && (mViewFlags & enabled_mask) == เปิดใช้งาน && li.montouchListener.ontouch (เหตุการณ์นี้)) {result = true; } if (! result && onTouchEvent (เหตุการณ์)) {result = true; }} ผลการส่งคืน; -เหตุการณ์ ontouch ที่เราตั้งไว้สำหรับมุมมองมีความสำคัญสูงกว่า หากการดำเนินการของ Ontouch ส่งคืนจริงแล้ว OnTouchEvent ของมุมมองจะไม่ไปที่มุมมอง เหตุการณ์การคลิกบางส่วนของเราได้รับการจัดการใน OnTouchEvent ซึ่งเป็นสาเหตุที่ OnTouch ส่งคืนจริงและเหตุการณ์ที่เกี่ยวข้องกับการคลิกของมุมมองจะไม่ถูกประมวลผล
สรุปสั้น ๆ ของกระบวนการนี้
เมื่อ ViewGroup ยอมรับเหตุการณ์ที่ส่งผ่านโดยผู้บังคับบัญชาหากเป็นจุดเริ่มต้นของชุดของเหตุการณ์สัมผัส (Action_down) ViewGroup จะตรวจสอบก่อนว่าจำเป็นต้องสกัดกั้นเหตุการณ์ (OnInterceptTouchevent การใช้งานเริ่มต้นของ ViewGroup โดยตรง ค้นหามุมมองที่คุณกำลังคลิกและโทรทันที DispatchTouchEvent ของมุมมองเป้าหมาย หาก DispatchTouchEvent ของมุมมองเป้าหมายส่งกลับเท็จก็คิดว่ามุมมองเป้าหมายอยู่ในตำแหน่งนั้นเท่านั้น ไม่ต้องการที่จะยอมรับเหตุการณ์นี้ แต่แค่อยากจะดูอย่างเงียบ ๆ (ฉันดูอย่างเงียบ ๆ ว่าคุณแกล้งทำเป็น*) ในเวลานี้ ViewGroup จะไปที่ DispatchTouchEvent เสร็จแล้ว!