فيما يلي مثال على تمرير الحدث بعد النقر على عرض.
أولاً ، قم بتحليل طريقة DispatchTouchEvent () في العرض ، وهي الطريقة الأولى للتنفيذ من خلال النقر على العرض.
public boolean dispatchtouchevent (حدث motionevent) {if (montouchListener! = null && (mviewflags & enable_mask) == enabled && montouchListener.ontouch (هذا ، الحدث)) {return true ؛ } إرجاع 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 () ؛ // الرد على النقر فوق "استراحة الحدث" ؛ حالة motionevent.action_down: .... break ؛ case motionevent.action_cancel: .... break ؛ حالة motionevent.action_move: ..... استراحة ؛ } إعادة صواب ؛ } إرجاع خطأ ؛إذا كان عنصر التحكم قابلاً للنقر أو Long_Clickable ، فيمكنه الاستجابة للحدث المقابل والعودة بشكل صحيح بعد اكتمال الاستجابة لمواصلة الاستجابة. على سبيل المثال ، عند النقر على حدث ما ، قم أولاً بالرد على Action_Down ، ثم كسر وإرجاع True ، ثم ارفع يدك ، ثم قم بتوزيعه من DispatchTouchEvent () ، ثم الرد على Action_up ، وسوف يستجيب للأداء () للنقر فوق "النقر فوق".
الرد على النقر فوق الأحداث
boolean public performclick () {sendAccessibilityevent (Accessibilityevent.type_view_clicked) ؛ if (monclickListener! = null) {playSoundEffect (SoundeffectConstants.click) ؛ MonclickListener.onclick (هذا) ؛ العودة صحيح. } إرجاع خطأ ؛}تنفيذ monclicklistener.onclick (هذا) ؛ وهذا هو ، وظيفة onClick () التي تربط المستمع.
النقاط الرئيسية:
كيفية استخدام الفرق بين Ontouch و Ontouchevent؟
إجابة:
عندما يتلقى عنصر التحكم في العرض حدث اللمس ، إذا كان عنصر التحكم مرتبطًا بمستمع OnTouchListener ويتم تمكين التحكم ، ثم قم بتنفيذ طريقة OnTouch (). إذا كان هذا صحيحًا ، فقد تم استهلاك حدث اللمس ولن يتم نقله بعد الآن ؛ إذا تم إرجاع خطأ ، فاستمر في الاتصال بحدث OnTouchevent ().
بعد تمرير حدث Android Touch إلى Decorview (A FrameLayout) في الجزء العلوي من النشاط ، سيتم تمريره طبقة حسب الطبقة عبر مجموعة ViewGroup إلى شجرة View ، وأخيراً تمرير الحدث إلى العرض الفعلي المستلم. فيما يلي بعض الطرق المهمة.
DispatchTouchEvent
عندما يتم تمرير حدث إلى مجموعة ViewGroup ، سيتم استدعاء DispatchTouchEvent. تم حذف الرمز
Boolean Public DispatchTouchEvent (MotionEvent ev) {Boolean Gearnled = false ؛ if (onFilterTouchEventForSecurity (EV)) {Final int Action = ev.getAction () ؛ Final int Actionmasked = Action & motionevent.action_mask ؛ // الانتباه 1: قم بمسح بعض الحالات عند الضغط عليها إذا (Actionmasked == motionevent.action_down) {cancandcleartouchTargets (EV) ؛ // لاحظ هذه الطريقة ResetTouchState () ؛ } // الانتباه 2: تحقق مما إذا كان المعترض المنطقي النهائي يجب اعتراضه ؛ // إذا قمت فقط بالضغط أو لديك طريقة عرض طفل للتعامل معها إذا (Actionmasked == motionevent.action_down || mfirsttouchTarget! = null) {النهائي boolean disallownterceptive = (mgroupflags & flag_disally_intercept)! = 0 ؛ if (! disallowntercept) {اعتراض = onInterceptTouchEvent (eV) ؛ ev.setAction (العمل) ؛ // استعادة الإجراء في حالة تغييره} آخر {اعتراض = false ؛ }} else {// إنها ليست بداية تسلسل الإجراء وليس هناك عرض فرعي للتعامل معه. تم اعتراضه مباشرة = صحيح ؛ } // لم يتم إلغاء الحدث ولا يتم اعتراضه بواسطة مجموعة ViewGroup الحالية. انتقل لمعرفة ما إذا كان هناك عرض فرعي تم الاستيلاء عليه إذا (! إلغاء &&! اعتراض) {// إذا كانت هذه هي بداية سلسلة من الإجراءات أو كان هناك مؤشر جديد مضغوط ، نحتاج إلى العثور على العرض الفرعي الذي يمكنه التعامل مع هذا المؤسس (Actionmasked == motionevent.action_down || motionevent.action_hover_move) {Final int ActionIndex = ev.getActionIndex () ؛ // دائمًا 0 لـ Down // القيود المذكورة أعلاه لنقطة اللمس 32 هل تسبب int int IdbitStoAssign النهائي = تقسيم؟ 1 << ev.getPointerId (ActionIndex): touchTarget.all_pointer_ids ؛ int failrencount النهائي = mchildrencount ؛ if (newTouchTarget == null && childrencount! = 0) {final float x = ev.getx (actionIndex) ؛ Final Float y = ev.gety (ActionIndex) ؛ // قم بفرز جميع الطفلين في مجموعة ViewGroup الحالية ، ووضعها في الطبقة العليا للبدء. ArrayList النهائي <View> preorderedList = BuildorDerDedChildList () ؛ Final Boolean CustomOrder = preDorderEdList == NULL && ISCHILDRENDRAWINGORDERNABD () ؛ الرؤية النهائية [] الأطفال = أطفال mchilder ؛ لـ (int i = childrencount-1 ؛ i> = 0 ؛ i--) {Final int childIndex = customorder؟ getChildDrawingorder (ChildCount ، i): i ؛ العرض النهائي الطفل = (preorderedList == NULL)؟ الأطفال [childIndex]: preorderedList.get (childIndex) ؛ // CanViewReceivePointerevents يمكن أن تقبل العرض المرئي // isTransformedTouchPointInview يحسب ما إذا كان يسقط على منطقة النقر إذا (! canvieweivepointerevents (child) ||! isTransformedTouchPointInview (x ، y ، الطفل ، null) يكمل؛ } // يمكنه التعامل مع ما إذا كان عرض هذا المؤشر قد عالج المؤشر السابق ، ثم استخدم newTouchTarget = getTouchTarget (طفل) ؛ if (newTouchTarget! = null) {// الطفل يتلقى بالفعل اللمس داخل حدوده. // أعطه المؤشر الجديد بالإضافة إلى تلك التي تتعامل معها. newTouchTarget.pointeridbits | = idbitStoAssign ؛ استراحة؛ }} // الانتباه 3: أرسلها مباشرة إلى عرض الطفل إذا كان (DispatchTransFormedTouchEvent (EV ، false ، child ، idbitstoassign)) {// يريد الطفل تلقي اللمس داخل حدوده. mlasttouchDownTime = ev.getDownTime () ؛ if (preorderedList! = null) {// ChildIndex يشير إلى قائمة مقدمة ، ابحث عن الفهرس الأصلي لـ (int j = 0 ؛ j <childrencount ؛ j ++) {if (childrendex] == mchildren [j]) {mlasttouchDownIndex = j ؛ استراحة؛ }}} آخر {mlastTouchDownIndex = childIndex ؛ } mlastTouchDownx = ev.getx () ؛ mlasttouchDowny = ev.gety () ؛ newTouchTarget = addTouchTarget (الطفل ، idbitStoAssign) ؛ بالفعل dispatchedtonewtouchTarget = true ؛ استراحة؛ }}}}}} // تم العثور على عرض الطفل الذي يتلقى الحدث من قبل. إذا كان فارغًا ، فهذا يعني أنه لا يتم الاستيلاء على أي رؤية طفل. تحتاج مجموعة ViewGroup الحالية إلى التعامل مع (mfirstTouchTarget == NULL) {// ViewGroup Handled = DispatchTransFormedTouchEvent (EV ، CancelChild ، Null ، touchTarget.all_pointer_ids) ؛ } else {if (perilesDaSteDtoneWtouchTarget) {// تجاهل بعض الكود إذا (dispatchTransFormedTouchEvent (ev ، cancelchild ، target.child ، target.pointeridbits)) {handled = true ؛ }}} إرجاع معالجة ؛}سيتم إشراك الاهتمام في الكود أعلاه في الجزء الأخير ، لذا انتبه إليه.
يجب الإشارة هنا إلى أنه يمكن تعيين مؤشرات مختلفة في سلسلة من الإجراءات لآراء مختلفة للرد. ستحافظ ViewGroup على مؤشر وقائمة من الأدوات التي تتعامل مع طرق العرض. تمثل الهدف اللطيف عرضًا فرعيًا يمكنه التعامل مع المؤشرات. بالطبع ، يمكن للمنظر التعامل مع مؤشرات متعددة ، مثل كلا الإصبعين في منطقة عرض فرعي. يستخدم TouchTarget INT داخليًا لتخزين المؤشر الذي يمكنه معالجته وبتات INT32 ، وهذا هو السبب في أن الطبقة العليا يمكن أن تسمح فقط بما يصل إلى 32 نقطة من اللمس في نفس الوقت.
دعونا نلقي نظرة على الكود في الانتباه 3. غالبًا ما نقول أنه إذا كانت الإرسالات من العرض تعود خاطئة ، فلا يمكن أن يتبعها الإجراء. لماذا هذا؟ لأنه إذا تم إرجاع FALSE عند الانتباه 3 ، فلن يتم تسجيله في الهدف اللطيف ، تعتقد ViewGroup أنه ليس لديك القدرة على التعامل مع هذا الحدث.
يمكنك أن ترى هنا أن ViewGroup تتعامل حقًا مع الأحداث في DispatchTransFormedTouchEvent ، اتبعها وألقي نظرة عليها:
DispatchTransFormedTouchEventPrivate Boolean DispatchTroaChevent (حدث MotionEvent ، إلغاء منطقي ، عرض الطفل ، int intsiredpointeridbits) {// لا معالجة فئة فرعية ، ثم اتركها إلى مجموعة ViewGroup للمعالجة إذا (الطفل == null) {super.dispatchtouchevent (محول) ؛ } else {Final Float OffsetX = mscrollx - child.mleft ؛ تعويم النهائي = mscrolly - child.mtop ؛ transformedevent.OffSetLocation (OffsetX ، OffSety) ؛ if (! child.hasidentityMatrix ()) {transformedevent.transform (child.getInversEmatrix ()) ؛ } معالجة = child.dispatchTouchEvent (transformedevent) ؛ } عودة معالجة ؛}يمكنك أن ترى أنه بغض النظر عن ماذا ، سيتم استدعاء DispatchTouchEvent من العرض ، وهو المكان الذي يتم فيه معالجة حدث النقر.
DispatchTouchEvent Public Boolean DispatchTouchEvent (حدث MotionEvent) {if (onfiltertoucheventforsecurity (event)) {// الحصول على حدث OnTouch للعرض أولاً ، إذا كان OnTouch يرجع المستمع الحقيقي li = mlistenerinfo ؛ if (li! = null && li.montouchListener! = null && (mviewflags & enupper_mask) == enabled && li.montouchListener.ontouch (هذا ، الحدث)) {result = true ؛ } if (! result && ontouchevent (event)) {result = true ؛ }} نتيجة الإرجاع ؛ }حدث OnTouch الذي حددناه لهذا العرض هو في أولوية أعلى. إذا كان تنفيذ OnTouch يعود صحيحًا ، فلن يذهب Ontouchevent من العرض إلى العرض. تتم معالجة بعض أحداث النقرات الخاصة بنا في Ontouchevent ، وهذا هو السبب في أن OnTouch يعيد صحيحًا ، ولن تتم معالجة الأحداث المتعلقة بالنقرات.
ملخص موجز لهذه العملية
عندما تقبل ViewGroup الأحداث التي تم نقلها من قبل الرؤساء ، إذا كانت بداية سلسلة من أحداث اللمس (Action_Down) ، فسيقوم ViewGroup أولاً بالتحقق مما إذا كان يحتاج إلى اعتراض الحدث (OnInterceptOuChevent ، فإن التنفيذ الافتراضي لمجموعة ViewGroup يرجع مباشرة إلى الإشارة إلى أنه لا يعترض) ، ثم يعرض ViewGroup جميع مشاهداته. ابحث عن العرض الذي تنقر عليه حاليًا واتصل على الفور بـ DispatchTouchEvent للعرض الهدف. إذا كان DispatchTouchEvent من طريقة العرض الهدف يعيد خطأ ، فإنه يعتقد أن طريقة العرض الهدف موجودة فقط في هذا الموضع. لا يريد قبول هذا الحدث ، ولكنه يريد فقط إخراج وجهة نظر بهدوء (أشاهدك بهدوء تتظاهر*). في هذا الوقت ، ستذهب ViewGroup أيضًا إلى DispatchTouchEvent ، تم القيام به!