Der beste Ort, um dies zu entmystifizieren, ist der Quellcode. Die Dokumente sind absolut unzureichend, um dies zu erklären.
dispatchTouchEvent ist tatsächlich in Activity, View und ViewGroup definiert. Stellen Sie sich das als einen Controller vor, der entscheidet, wie die Berührungsereignisse weitergeleitet werden.
Der einfachste Fall ist beispielsweise der von View.dispatchTouchEvent, bei dem das Berührungsereignis entweder an OnTouchListener.onTouch weitergeleitet wird, sofern es definiert ist, oder an die Erweiterungsmethode onTouchEvent .
Für ViewGroup.dispatchTouchEvent sind die Dinge viel komplizierter. Es muss herausfinden, welche seiner untergeordneten Ansichten das Ereignis erhalten soll (durch Aufrufen von child.dispatchTouchEvent). Dies ist im Grunde ein Treffer-Test-Algorithmus, bei dem Sie herausfinden, welches Begrenzungsrechteck der untergeordneten Ansicht die Berührungspunktkoordinaten enthält.
Bevor das Ereignis jedoch an die entsprechende untergeordnete Ansicht gesendet werden kann, kann der Elternteil das Ereignis ausspionieren und / oder abfangen. Dafür ist onInterceptTouchEvent da. Daher wird diese Methode zuerst aufgerufen, bevor der Treffer-Test durchgeführt wird. Wenn das Ereignis entführt wurde (indem von onInterceptTouchEvent true zurückgegeben wird), wird ACTION_CANCEL an die untergeordneten Ansichten gesendet , damit diese ihre Verarbeitung von Berührungsereignissen (von früheren Berührungsereignissen) abbrechen können Alle Berührungsereignisse auf übergeordneter Ebene werden an onTouchListener.onTouch (falls definiert) oder onTouchEvent () gesendet . Auch in diesem Fall wird onInterceptTouchEvent nie wieder aufgerufen.
Möchten Sie sogar [Activity | ViewGroup | View] .dispatchTouchEvent überschreiben? Wenn Sie kein benutzerdefiniertes Routing durchführen, sollten Sie dies wahrscheinlich nicht tun.
Die Haupterweiterungsmethoden sind ViewGroup.onInterceptTouchEvent, wenn Sie Berührungsereignisse auf übergeordneter Ebene ausspionieren und / oder abfangen möchten, und View.onTouchListener / View.onTouchEvent für die Behandlung von Hauptereignissen.
Alles in allem ist das Design imo zu kompliziert, aber Android Apis tendieren eher zur Flexibilität als zur Einfachheit.
Denn dies ist das erste Ergebnis bei Google. Ich möchte mit Ihnen einen großartigen Vortrag von Dave Smith auf Youtube teilen : Beherrschen des Android Touch Systems und der Folien finden Sie hier . Es gab mir ein gutes tiefes Verständnis für das Android Touch System:
Wie die Aktivität mit Berührungen umgeht:
Wie die Ansicht Griff berühren:
Wie eine ViewGroup mit Berührungen umgeht :
Er bietet auch einen Beispielcode für benutzerdefinierte Berührungen unter github.com/devunwired/ .
Antwort: Grundsätzlich
dispatchTouchEvent()
wird das auf jederView
Ebene aufgerufen , um festzustellen, ob aView
an einer fortlaufenden Geste interessiert ist. In einesViewGroup
derViewGroup
hat die Möglichkeit , die Touch - Ereignisse in seinem zu stehlendispatchTouchEvent()
-Methode, bevor es nennen würdedispatchTouchEvent()
auf den Kindern. DasViewGroup
würde den Versand nur stoppen, wenn dieViewGroup
onInterceptTouchEvent()
-method true zurückgibt. Der Unterschied besteht darin, dass derdispatchTouchEvent()
Versand erfolgtMotionEvents
und angegebenonInterceptTouchEvent
wird, ob er abfangen soll (nichtMotionEvent
an Kinder versenden ) oder nicht (an Kinder versenden) .Sie können sich vorstellen, dass der Code einer ViewGroup mehr oder weniger dies tut (sehr vereinfacht):
quelle
Ergänzende Antwort
Hier sind einige visuelle Ergänzungen zu den anderen Antworten. Meine vollständige Antwort ist hier .
Die
dispatchTouchEvent()
Methode aViewGroup
verwendet, umonInterceptTouchEvent()
zu wählen, ob das Berührungsereignis (mitonTouchEvent()
) sofort behandelt werden soll oder ob diedispatchTouchEvent()
Methoden seiner untergeordneten Elemente weiterhin benachrichtigt werden sollen.quelle
Es gibt viel Verwirrung über diese Methoden, aber es ist eigentlich nicht so kompliziert. Die meiste Verwirrung ist, weil:
View/ViewGroup
oder eines seiner Kinder nicht zurück wahr inonTouchEvent
,dispatchTouchEvent
undonInterceptTouchEvent
werden NUR für aufgerufen werdenMotionEvent.ACTION_DOWN
. Ohne ein True fromonTouchEvent
geht die übergeordnete Ansicht davon aus , dass Ihre Ansicht die MotionEvents nicht benötigt.MotionEvent.ACTION_DOWN
, selbst wenn Ihre ViewGroup in true true zurückgibtonTouchEvent
.Der Verarbeitungsauftrag lautet wie folgt:
dispatchTouchEvent
wird genannt.onInterceptTouchEvent
wird aufgerufenMotionEvent.ACTION_DOWN
oder wenn eines der untergeordneten Elemente der ViewGroup true in zurückgegeben hatonTouchEvent
.onTouchEvent
wird zuerst für die untergeordneten Elemente der ViewGroup aufgerufen, und wenn keines der untergeordneten Elemente true zurückgibt, wird es für die aufgerufenView/ViewGroup
.Wenn Sie eine Vorschau
TouchEvents/MotionEvents
anzeigen möchten, ohne die Ereignisse für Ihre Kinder zu deaktivieren, müssen Sie zwei Dinge tun:dispatchTouchEvent
um eine Vorschau des Ereignisses anzuzeigen und zurückzukehrensuper.dispatchTouchEvent(ev)
.onTouchEvent
und true zurückgeben, sonst erhalten Sie keineMotionEvent
außerMotionEvent.ACTION_DOWN
.Wenn Sie eine Geste wie ein Wischereignis erkennen möchten, ohne andere Ereignisse für Ihre Kinder zu deaktivieren, solange Sie die Geste nicht erkannt haben, können Sie dies folgendermaßen tun:
onInterceptTouchEvent
Geben Sie true zurück, wenn Ihr Flag gesetzt ist, um die MotionEvent-Verarbeitung durch Ihre Kinder abzubrechen. Dies ist auch ein praktischer Ort, um Ihre Flagge zurückzusetzen, da onInterceptTouchEvent erst beim nächsten Mal wieder aufgerufen wirdMotionEvent.ACTION_DOWN
.Beispiel für Überschreibungen in a
FrameLayout
(mein Beispiel in ist C #, da ich mit Xamarin Android programmiere, aber die Logik in Java ist dieselbe):quelle
Auf dieser Webseite http://doandroids.com/blogs/tag/codeexample/ bin ich auf eine sehr intuitive Erklärung gestoßen . Von dort genommen:
quelle
dispatchTouchEvent-Handles vor onInterceptTouchEvent.
Anhand dieses einfachen Beispiels:
Sie können sehen, dass das Protokoll wie folgt aussehen wird:
Wenn Sie also mit diesen beiden Handlern arbeiten, verwenden Sie dispatchTouchEvent, um das Ereignis in erster Instanz zu behandeln, das an onInterceptTouchEvent gesendet wird.
Ein weiterer Unterschied besteht darin, dass wenn dispatchTouchEvent 'false' zurückgibt, das Ereignis nicht an das untergeordnete Element weitergegeben wird, in diesem Fall an EditText. Wenn Sie in onInterceptTouchEvent false zurückgeben, wird das Ereignis dennoch an EditText gesendet
quelle
Kurze Antwort:
dispatchTouchEvent()
wird aufgerufen, zuerst von allen.Kurzer Rat: sollte nicht außer Kraft gesetzt werden,
dispatchTouchEvent()
da es schwer zu kontrollieren ist, manchmal kann es Ihre Leistung verlangsamen. IMHO, ich schlage vor, zu überschreibenonInterceptTouchEvent()
.Da in den meisten Antworten das Flow-Touch-Ereignis in Aktivität / Ansichtsgruppe / Ansicht ziemlich deutlich erwähnt wird, füge ich in
ViewGroup
(IgnorierendispatchTouchEvent()
) nur weitere Details zum Code dieser Methoden hinzu :onInterceptTouchEvent()
wird zuerst aufgerufen, das ACTION-Ereignis wird jeweils down -> move -> up aufgerufen. Es gibt 2 Fälle:Wenn Sie in 3 Fällen false zurückgeben (ACTION_DOWN, ACTION_MOVE, ACTION_UP), wird berücksichtigt, dass der Elternteil dieses Berührungsereignis nicht benötigt , sodass
onTouch()
die Eltern niemalsonTouch()
anrufen , sondern die Kinder stattdessen anrufen . Bitte beachten Sie jedoch:onInterceptTouchEvent()
erhalten weiterhin ein Touch-Ereignis, solange ihre Kinder nicht anrufenrequestDisallowInterceptTouchEvent(true)
.onTouch()
die Eltern zurück.Umgekehrt, wenn Sie true zurückgeben , stiehlt der Elternteil dieses Berührungsereignis sofort und
onInterceptTouchEvent()
stoppt sofort, anstatt dassonTouch()
die Eltern aufgerufen werden und alleonTouch()
Kinder das letzte Aktionsereignis erhalten - ACTION_CANCEL ( dh die Eltern) Touch-Ereignis gestohlen, und Kinder können von da an nicht mehr damit umgehen. Der Fluss deronInterceptTouchEvent()
Rückgabe false ist normal, aber es gibt eine kleine Verwechslung mit dem Fall return true, daher liste ich ihn hier auf:onTouch()
Die Eltern erhalten erneut ACTION_DOWN und die folgenden Aktionen (ACTION_MOVE, ACTION_UP).onTouch()
Die Eltern erhalten die nächste ACTION_MOVE (nicht dieselbe ACTION_MOVE inonInterceptTouchEvent()
) und die folgenden Aktionen (ACTION_MOVE, ACTION_UP).onTouch()
die Eltern überhaupt NICHT aufgerufen werden, da es für die Eltern zu spät ist, ein Berührungsereignis zu stehlen.Eine weitere wichtige Sache ist, dass ACTION_DOWN des Ereignisses in
onTouch()
bestimmt, ob die Ansicht mehr Aktion von diesem Ereignis erhalten möchte oder nicht. Wenn die Ansicht bei ACTION_DOWN in true zurückgibtonTouch()
, bedeutet dies, dass die Ansicht bereit ist, weitere Aktionen von diesem Ereignis zu erhalten. Andernfalls bedeutet die Rückgabe von false bei ACTION_DOWN inonTouch()
, dass die Ansicht von diesem Ereignis keine weitere Aktion erhält.quelle
Die Antwort finden Sie in diesem Video https://www.youtube.com/watch?v=SYoN-OvdZ3M&list=PLonJJ3BVjZW6CtAMbJz1XD8ELUs1KXaTD&index=19 und den nächsten 3 Videos. Alle Berührungsereignisse werden sehr gut erklärt, es ist sehr klar und voller Beispiele.
quelle
Der folgende Code in einer ViewGroup-Unterklasse verhindert, dass übergeordnete Container Berührungsereignisse empfangen:
Ich habe dies mit einem benutzerdefinierten Overlay verwendet, um zu verhindern, dass Hintergrundansichten auf Berührungsereignisse reagieren.
quelle
Der Hauptunterschied :
quelle
ViewGroups
onInterceptTouchEvent()
ist immer der Einstiegspunkt für einACTION_DOWN
Ereignis, das als erstes Ereignis auftritt.Wenn ViewGroup diese Geste verarbeiten soll, geben Sie true from zurück
onInterceptTouchEvent()
. Bei der Rückkehr wahr, Viewgroup deronTouchEvent()
alle nachfolgenden Ereignisse bis zum nächsten erhaltenACTION_UP
oderACTION_CANCEL
, und in den meisten Fällen die Berührungsereignisse zwischenACTION_DOWN
undACTION_UP
oderACTION_CANCEL
sindACTION_MOVE
, die normalerweise als Lauf / schleudern Gesten erkannt werden.Wenn Sie false von zurückgeben
onInterceptTouchEvent()
, wird die ZielansichtonTouchEvent()
aufgerufen. Es wird für nachfolgende Nachrichten wiederholt, bis Sie true von zurückgebenonInterceptTouchEvent()
.Quelle: http://neevek.net/posts/2013/10/13/implementing-onInterceptTouchEvent-and-onTouchEvent-for-ViewGroup.html
quelle
Sowohl Activity als auch View verfügen über die Methoden dispatchTouchEvent () und onTouchEvent. Die ViewGroup verfügt ebenfalls über diese Methoden, jedoch über eine andere Methode namens onInterceptTouchEvent. Der Rückgabetyp dieser Methoden ist boolesch. Sie können die Versandroute über den Rückgabewert steuern.
Der Ereignisversand in Android beginnt unter Aktivität-> Ansichtsgruppe-> Ansicht.
quelle
quelle
Kleine Antwort:
onInterceptTouchEvent steht vor setOnTouchListener.
quelle