java - एंड्रॉइड: इंटरसेप्ट टचवेन्ट और प्रेषण टचवेन्ट के बीच अंतर?




android event-handling (10)

Android में onInterceptTouchEvent और dispatchTouchEvent onInterceptTouchEvent बीच क्या अंतर है?

एंड्रॉइड डेवलपर गाइड के मुताबिक, दोनों तरीकों का उपयोग टच इवेंट ( MotionEvent ) को रोकने के लिए किया जा सकता है, लेकिन क्या अंतर है?

onInterceptTouchEvent , dispatchTouchEvent और onTouchEvent कैसे दृश्य (दृश्य समूह) के पदानुक्रम के भीतर एक साथ बातचीत करते हैं?


पूरक उत्तर

अन्य उत्तरों के लिए यहां कुछ दृश्य पूरक हैं। मेरा पूरा जवाब here ।

dispatchTouchEvent() onInterceptTouchEvent() dispatchTouchEvent() विधि onInterceptTouchEvent() पर यह चुनने के लिए उपयोग onInterceptTouchEvent() कि इसे तुरंत टच इवेंट ( onInterceptTouchEvent() साथ) या अपने बच्चों के dispatchTouchEvent() onInterceptTouchEvent() dispatchTouchEvent() विधियों को सूचित करना जारी रखना चाहिए या नहीं।


ViewGroup'sInterceptTouchEvent onInterceptTouchEvent() हमेशा ACTION_DOWN ईवेंट के लिए प्रविष्टि बिंदु होता है जो पहली घटना होती है।

यदि आप इस इशारा को संसाधित करने के लिए onInterceptTouchEvent() चाहते हैं, तो onInterceptTouchEvent() से सत्य लौटें। सत्य लौटने पर, ViewGroup के onTouchEvent() को अगले ACTION_UP या ACTION_CANCEL तक आने वाली सभी घटनाएं प्राप्त ACTION_CANCEL , और ज्यादातर मामलों में, ACTION_DOWN और ACTION_UP या ACTION_CANCEL बीच स्पर्श ईवेंट ACTION_CANCEL हैं, जिन्हें आमतौर पर स्क्रॉलिंग / ACTION_MOVE जेस्चर के रूप में पहचाना जाएगा।

अगर आप onInterceptTouchEvent() से झूठी वापसी करते हैं, तो लक्ष्य दृश्य पर onInterceptTouchEvent() onTouchEvent() को कॉल किया जाएगा। इसे बाद के संदेशों के लिए दोहराया जाएगा जब तक कि आप onInterceptTouchEvent() से सच नहीं onInterceptTouchEvent()

स्रोत: http://neevek.net/posts/2013/10/13/implementing-onInterceptTouchEvent-and-onTouchEvent-for-ViewGroup.html


इन तरीकों के बारे में बहुत भ्रम है, लेकिन वास्तव में यह जटिल नहीं है। अधिकांश भ्रम है क्योंकि:

  1. यदि आपका View/ViewGroup या उसके कोई भी बच्चे onInterceptTouchEvent में सत्य नहीं लौटाता है, तो dispatchTouchEvent onInterceptTouchEvent और onInterceptTouchEvent को केवल onInterceptTouchEvent लिए बुलाया जाएगा। onTouchEvent से सच्चाई के बिना, मूल दृश्य आपके विचार को मोशनवेन्ट्स की आवश्यकता नहीं मानता है।
  2. जब टचवेन्ट पर व्यू ग्रुप के कोई भी बच्चे सही नहीं होते हैं, तो इंटरसेप्ट टचएवेंट को केवल मोशनइवेंट.एक्शन_DOWN के लिए बुलाया जाएगा, भले ही आपका व्यू ग्रुप ऑन टचएवेंट में सत्य हो।

प्रसंस्करण आदेश इस तरह है:

  1. dispatchTouchEvent कहा जाता है।
  2. onInterceptTouchEvent को MotionEvent.ACTION_DOWN लिए बुलाया जाता है या जब ViewGroup के किसी भी बच्चे onTouchEvent में सत्य onTouchEvent
  3. ऑन onTouchEvent को पहली बार View/ViewGroup के बच्चों पर बुलाया जाता है और जब कोई भी बच्चा सच नहीं होता है तो इसे View/ViewGroup पर बुलाया जाता है।

यदि आप अपने बच्चों पर घटनाओं को अक्षम किए बिना TouchEvents/MotionEvents का पूर्वावलोकन करना चाहते हैं, तो आपको दो चीज़ें करना होगा:

  1. ईवेंट का पूर्वावलोकन करने और super.dispatchTouchEvent(ev) वापस करने के लिए dispatchTouchEvent को ओवरराइड करें;
  2. onTouchEvent ओवरराइड करें और सत्य लौटें, अन्यथा आपको MotionEvent को छोड़कर कोई MotionEvent नहीं मिलेगा।

यदि आप स्वाइप ईवेंट की तरह कुछ इशारा पता लगाना चाहते हैं, तब तक जब तक आपको इशारा नहीं पता चला, तब तक आपके बच्चों पर अन्य घटनाओं को अक्षम किए बिना, आप इसे इस तरह से कर सकते हैं:

  1. ऊपर वर्णित मोशनवेन्ट्स का पूर्वावलोकन करें और जब आपने अपना इशारा पता लगाया तो ध्वज सेट करें।
  2. onInterceptTouchEvent सही लौटें जब आपका ध्वज आपके बच्चों द्वारा मोशनएवेंट प्रोसेसिंग को रद्द करने के लिए सेट हो। यह आपके ध्वज को रीसेट करने के लिए एक सुविधाजनक स्थान भी है, क्योंकि InterceptTouchEvent को अगले MotionEvent.ACTION_DOWN तक फिर से नहीं बुलाया जाएगा।

FrameLayout में ओवरराइड का उदाहरण (मेरा उदाहरण सी # है क्योंकि मैं एक्समरिन एंड्रॉइड के साथ प्रोग्रामिंग कर रहा हूं, लेकिन तर्क जावा में समान है):

public override bool DispatchTouchEvent(MotionEvent e)
{
    // Preview the touch event to detect a swipe:
    switch (e.ActionMasked)
    {
        case MotionEventActions.Down:
            _processingSwipe = false;
            _touchStartPosition = e.RawX;
            break;
        case MotionEventActions.Move:
            if (!_processingSwipe)
            {
                float move = e.RawX - _touchStartPosition;
                if (move >= _swipeSize)
                {
                    _processingSwipe = true;
                    _cancelChildren = true;
                    ProcessSwipe();
                }
            }
            break;
    }
    return base.DispatchTouchEvent(e);
}

public override bool OnTouchEvent(MotionEvent e)
{
    // To make sure to receive touch events, tell parent we are handling them:
    return true;
}

public override bool OnInterceptTouchEvent(MotionEvent e)
{
    // Cancel all children when processing a swipe:
    if (_cancelChildren)
    {
        // Reset cancel flag here, as OnInterceptTouchEvent won't be called until the next MotionEventActions.Down:
        _cancelChildren = false;
        return true;
    }
    return false;
}

इसे नष्ट करने के लिए सबसे अच्छी जगह स्रोत कोड है। दस्तावेजों को समझाने के बारे में अपर्याप्त हैं।

प्रेषण टचएवेंट वास्तव में गतिविधि, दृश्य और दृश्य समूह पर परिभाषित किया गया है। इसे एक नियंत्रक के रूप में सोचें जो तय करता है कि टच इवेंट्स को कैसे रूट किया जाए।

उदाहरण के लिए, सबसे सरल मामला View.dispatchTouchEvent का है जो टच इवेंट को या तो ऑन टच लिस्टनर.ऑन टच पर रूट करेगा यदि यह परिभाषित किया गया है या टचएवेंट पर एक्सटेंशन विधि के लिए।

ViewGroup.dispatchTouchEvent चीजों के लिए रास्ता अधिक जटिल हैं। इसे पता लगाने की जरूरत है कि उसके बच्चे के विचारों में से कौन सा ईवेंट ईवेंट प्राप्त करना चाहिए (child.dispatchTouchEvent को कॉल करके)। यह मूल रूप से एक हिट परीक्षण एल्गोरिदम है जहां आप पता लगाते हैं कि कौन से बच्चे के दृश्य के बाध्य आयत में टच पॉइंट निर्देशांक होते हैं।

लेकिन इससे पहले कि यह उचित बच्चे के दृश्य में घटना को प्रेषित कर सके, माता-पिता सभी को एक साथ जासूसी कर सकते हैं और / या रोक सकते हैं। इन्टरसेप्ट टचवेन्ट पर यही है। तो यह हिट परीक्षण करने से पहले इस विधि को पहले कॉल करता है और यदि ईवेंट को अपहरण कर लिया गया था (इंटरसेप्ट टचवेन्ट से सच लौटकर) यह बच्चे के विचारों में ACTION_CANCEL भेजता है ताकि वे अपने स्पर्श ईवेंट प्रसंस्करण (पिछले स्पर्श ईवेंट से) और उसके बाद से अभिभावक स्तर पर सभी स्पर्श घटनाओं को टच लिस्टनर.ऑन टच (यदि परिभाषित किया गया है) या टचएवेंट () पर भेजा जाता है। इसके अलावा, उस मामले में, इंटरसेप्ट टचवेन्ट को फिर कभी नहीं कहा जाता है।

क्या आप [गतिविधि | व्यू ग्रुप | व्यू] .dispatchTouchEvent को ओवरराइड करना चाहते हैं? जब तक आप कुछ कस्टम रूटिंग नहीं कर रहे हैं तो आपको शायद नहीं करना चाहिए।

मुख्य एक्सटेंशन विधियां ViewGroup.onInterceptTouchEvent हैं यदि आप मूल ईवेंट हैंडलिंग के लिए अभिभावक स्तर और View.onTouchListener / View.onTouchEvent पर टच ईवेंट को जासूसी और / या अवरुद्ध करना चाहते हैं।

सब कुछ अपने अत्यधिक जटिल डिजाइन इमो में लेकिन एंड्रॉइड एपिस सादगी की तुलना में लचीलापन की ओर अधिक दुबला है।


गतिविधि और दृश्य दोनों में विधि प्रेषण है टचवेन्ट () और टचवेन्ट। व्यू ग्रुप में यह विधियां भी हैं, लेकिन इनसेप्टसेप्ट टचएवेंट पर एक और तरीका है। उन विधियों का रिटर्न प्रकार बुलियन है, आप रिटर्न वैल्यू के माध्यम से प्रेषण मार्ग को नियंत्रित कर सकते हैं।

एंड्रॉइड में इवेंट प्रेषण गतिविधि-> व्यू ग्रुप-> व्यू से शुरू होता है।


छोटा जवाब:

OnInterceptTouchEvent setOnTouchListener से पहले आता है।


मुख्य अंतर :

• Activity.dispatchTouchEvent (मोशनवेन्ट) - यह आपकी गतिविधि को विंडो पर भेजे जाने से पहले सभी स्पर्श ईवेंट को अवरुद्ध करने की अनुमति देता है।
• ViewGroup.onInterceptTouchEvent (मोशनवेन्ट) - यह एक व्यू ग्रुप को घटनाओं को देखने की अनुमति देता है क्योंकि उन्हें बच्चे के दृश्यों में भेजा जाता है।


मैं इस वेबपृष्ठ http://doandroids.com/blogs/tag/codeexample/ पर बहुत सहज ज्ञान युक्त स्पष्टीकरण में आया था। वहां से लिया गया:

  • बूलियन ऑन टचवेन्ट (मोशनवेन्ट ईवी) - जब भी इस दृश्य के साथ एक स्पर्श घटना लक्ष्य के रूप में पहचाना जाता है
  • बूलियन ऑनइंटरसेप्ट टचवेन्ट (मोशनवेन्ट ईवी) - जब भी इस व्यू ग्रुप या उसके बच्चे के साथ लक्ष्य के रूप में एक स्पर्श घटना का पता लगाया जाता है। यदि यह फ़ंक्शन सत्य लौटाता है, तो मोशनवेन्ट को अवरुद्ध कर दिया जाएगा, जिसका अर्थ है कि यह बच्चे को नहीं भेजा जाएगा, बल्कि इस दृश्य के टचवेन्ट के लिए।

संक्षिप्त उत्तर: dispatchTouchEvent() को सबसे पहले बुलाया जाएगा।

लघु सलाह: dispatchTouchEvent() ओवरराइड नहीं करना चाहिए क्योंकि इसे नियंत्रित करना मुश्किल है, कभी-कभी यह आपके प्रदर्शन को धीमा कर सकता है। onInterceptTouchEvent() , मैं onInterceptTouchEvent() ओवरराइड करने का सुझाव देता हूं।

चूंकि अधिकतर उत्तर गतिविधि / दृश्य समूह / दृश्य पर प्रवाह स्पर्श ईवेंट के बारे में स्पष्ट रूप से उल्लेख करते हैं, इसलिए मैं केवल ViewGroup में इन विधियों पर कोड के बारे में अधिक जानकारी जोड़ता हूं ( dispatchTouchEvent() ViewGroup dispatchTouchEvent() अनदेखा कर रहा हूं):

onInterceptTouchEvent() को पहले कहा जाएगा, क्रिया घटना क्रमशः नीचे -> move -> up कहा जाएगा। 2 मामले हैं:

  1. यदि आप 3 मामलों (ACTION_DOWN, ACTION_MOVE, ACTION_UP) में झूठी वापसी करते हैं , तो यह विचार करेगा क्योंकि माता-पिता को इस स्पर्श ईवेंट की आवश्यकता नहीं होगी , इसलिए माता-पिता के onTouch() पर कभी भी कॉल नहीं होता है , लेकिन बच्चों के onTouch() के बजाय कॉल करेंगे ; हालांकि कृपया ध्यान दें:

    • onInterceptTouchEvent() अभी भी टच इवेंट प्राप्त करना जारी रखता है, जब तक कि उसके बच्चे onInterceptTouchEvent() नहीं करते हैं requestDisallowInterceptTouchEvent(true)
    • अगर उस घटना को प्राप्त करने वाले कोई बच्चे नहीं हैं (यह 2 मामलों में हो सकता है: उपयोगकर्ताओं को स्पर्श करने की स्थिति में कोई बच्चा नहीं है, या बच्चे हैं लेकिन यह ACTION_DOWN पर झूठा लौटाता है), माता-पिता उस घटना को वापस onTouch() पर भेज देंगे माता-पिता।
  2. इसके विपरीत, यदि आप सच वापस आते हैं , तो माता-पिता तुरंत इस स्पर्श ईवेंट को चुरा लेंगे , और onInterceptTouchEvent() तुरंत बंद हो जाएंगे, इसके बजाय माता-पिता के onTouch() के साथ-साथ बच्चों के सभी onTouch() को अंतिम क्रिया ईवेंट प्राप्त होगा - ACTION_CANCEL (इस प्रकार, इसका मतलब है कि माता-पिता ने टच इवेंट चुरा लिया है, और बच्चे इसे तब से संभाल नहीं सकते हैं)। onInterceptTouchEvent() झूठी वापसी का प्रवाह सामान्य है, लेकिन वापसी के मामले में थोड़ा उलझन है, इसलिए मैं इसे यहां सूचीबद्ध करता हूं:

    • ACTION_DOWN पर सही लौटें, माता-पिता के onTouch() को ACTION_DOWN फिर से और क्रियाओं (ACTION_MOVE, ACTION_UP) के बाद प्राप्त होगा।
    • ACTION_MOVE पर सत्य लौटें, माता-पिता के onTouch() को अगले ACTION_MOVE प्राप्त होगा (एंटरसेप्ट onInterceptTouchEvent() ) पर और उसी क्रिया (ACTION_MOVE, ACTION_UP) में एक ही ACTION_MOVE नहीं होगा।
    • माता-पिता के ACTION_UP पर, onTouch() पर वापस लौटें, क्योंकि माता-पिता के लिए स्पर्श ईवेंट चोरी करने में बहुत देर हो चुकी है।

एक और बात महत्वपूर्ण है कि onTouch() में ईवेंट की ACTION_DOWN यह निर्धारित करेगी कि दृश्य उस घटना से अधिक कार्रवाई प्राप्त करना चाहेगा या नहीं। यदि दृश्य onTouch() में ACTION_DOWN पर सत्य लौटाता है, तो इसका अर्थ यह है कि दृश्य उस ईवेंट से अधिक कार्रवाई प्राप्त करने के इच्छुक है। अन्यथा, onTouch() में ACTION_DOWN पर झूठी वापसी का अर्थ यह होगा कि दृश्य उस घटना से और अधिक कार्रवाई नहीं करेगा।


public boolean dispatchTouchEvent(MotionEvent ev){
    boolean consume =false;
    if(onInterceptTouchEvent(ev){
        consume = onTouchEvent(ev);
    }else{
        consume = child.dispatchTouchEvent(ev);
    }
}




android-touch-event