O melhor lugar para desmistificar isso é o código fonte. Os documentos são lamentavelmente inadequados para explicar isso.
dispatchTouchEvent é realmente definido em Activity, View e ViewGroup. Pense nisso como um controlador que decide como rotear os eventos de toque.
Por exemplo, o caso mais simples é o de View.dispatchTouchEvent, que encaminhará o evento de toque para OnTouchListener.onTouch, se estiver definido, ou para o método de extensão onTouchEvent .
Para ViewGroup.dispatchTouchEvent, as coisas são muito mais complicadas. Ele precisa descobrir qual das visualizações filho deve receber o evento (chamando child.dispatchTouchEvent). Esse é basicamente um algoritmo de teste de acerto, no qual você descobre qual retângulo delimitador da visualização filho contém as coordenadas do ponto de contato.
Mas antes que ele possa despachar o evento para a visão filho apropriada, o pai pode espionar e / ou interceptar o evento todos juntos. É para isso que existe o onInterceptTouchEvent . Portanto, ele chama esse método antes de fazer o teste de ocorrência e, se o evento foi seqüestrado (retornando true de onInterceptTouchEvent), ele envia um ACTION_CANCEL para as visualizações filho, para que possam abandonar o processamento de eventos de toque (de eventos de toque anteriores) e a partir de então todos os eventos de toque no nível pai são despachados para onTouchListener.onTouch (se definido) ou onTouchEvent (). Também nesse caso, onInterceptTouchEvent nunca é chamado novamente.
Você gostaria de substituir [Activity | ViewGroup | View] .dispatchTouchEvent? A menos que você esteja fazendo algum roteamento personalizado, provavelmente não deveria.
Os principais métodos de extensão são ViewGroup.onInterceptTouchEvent se você deseja espionar e / ou interceptar o evento de toque no nível pai e View.onTouchListener / View.onTouchEvent para manipulação de eventos principais.
Em suma, seu design excessivamente complicado, mas as APIs do Android inclinam-se mais para a flexibilidade do que para a simplicidade.
Porque este é o primeiro resultado no Google. Quero compartilhar com você uma ótima palestra de Dave Smith no Youtube: Dominar o Android Touch System e os slides estão disponíveis aqui . Isso me deu um bom entendimento profundo sobre o Android Touch System:
Como a Atividade lida com o toque:
Como o View lida com o toque:
Como um ViewGroup lida com o toque:
Ele também fornece um exemplo de código de toque personalizado em github.com/devunwired/ .
Resposta: Basicamente,
dispatchTouchEvent()
é chamado em todas asView
camadas para determinar se aView
está interessado em um gesto contínuo. Em umViewGroup
oViewGroup
tem a capacidade de roubar os eventos de toque em suadispatchTouchEvent()
-method, antes que ele chamariadispatchTouchEvent()
sobre as crianças. OViewGroup
interromperia o envio apenas se oViewGroup
onInterceptTouchEvent()
método-retornar true. A diferença é quedispatchTouchEvent()
está despachandoMotionEvents
eonInterceptTouchEvent
informa se deve interceptar (não despacharMotionEvent
para crianças) ou não (despachar para crianças) .Você pode imaginar o código de um ViewGroup fazendo mais ou menos isso (muito simplificado):
fonte
Resposta complementar
Aqui estão alguns suplementos visuais para as outras respostas. Minha resposta completa está aqui .
O
dispatchTouchEvent()
método de umViewGroup
usaonInterceptTouchEvent()
para escolher se ele deve manipular imediatamente o evento de toque (comonTouchEvent()
) ou continuar notificando osdispatchTouchEvent()
métodos de seus filhos.fonte
Há muita confusão sobre esses métodos, mas na verdade não é tão complicado. A maior parte da confusão é porque:
View/ViewGroup
ou algum de seus filhos não retornar verdadeiroonTouchEvent
,dispatchTouchEvent
eonInterceptTouchEvent
SOMENTE será necessárioMotionEvent.ACTION_DOWN
. Sem um true deonTouchEvent
, a visualização principal assumirá que sua visualização não precisa dos MotionEvents.MotionEvent.ACTION_DOWN
, mesmo que seu ViewGroup retorne true emonTouchEvent
.A ordem de processamento é assim:
dispatchTouchEvent
é chamado.onInterceptTouchEvent
é chamadoMotionEvent.ACTION_DOWN
ou quando qualquer um dos filhos do ViewGroup retornou trueonTouchEvent
.onTouchEvent
é chamado primeiro pelos filhos do ViewGroup e, quando nenhum dos filhos retorna verdadeiro, é chamado noView/ViewGroup
.Se você deseja visualizar
TouchEvents/MotionEvents
sem desativar os eventos em seus filhos, faça duas coisas:dispatchTouchEvent
para visualizar o evento e retornarsuper.dispatchTouchEvent(ev)
;onTouchEvent
e retorne true, caso contrário você não receberá nada,MotionEvent
excetoMotionEvent.ACTION_DOWN
.Se você deseja detectar algum gesto como um evento de furto, sem desativar outros eventos em seus filhos, desde que você não tenha detectado o gesto, você pode fazê-lo assim:
onInterceptTouchEvent
quando seu sinalizador estiver definido para cancelar o processamento do MotionEvent por seus filhos. Este também é um local conveniente para redefinir seu sinalizador, porque onInterceptTouchEvent não será chamado novamente até a próximaMotionEvent.ACTION_DOWN
.Exemplo de substituições em a
FrameLayout
(meu exemplo em C # é como estou programando com o Xamarin Android, mas a lógica é a mesma em Java):fonte
Eu vim através de uma explicação muito intuitiva nesta página da web http://doandroids.com/blogs/tag/codeexample/ . Retirado de lá:
fonte
os identificadores dispatchTouchEvent antes de onInterceptTouchEvent.
Usando este exemplo simples:
Você pode ver que o log será como:
Portanto, caso você esteja trabalhando com esses 2 manipuladores, use dispatchTouchEvent para manipular, em primeira instância, o evento, que irá para onInterceptTouchEvent.
Outra diferença é que, se dispatchTouchEvent retornar 'false', o evento não será propagado para o filho, neste caso, o EditText, enquanto que se você retornar false em onInterceptTouchEvent, o evento ainda será despachado para o EditText
fonte
Resposta curta:
dispatchTouchEvent()
será chamado em primeiro lugar.Conselho breve: não deve substituir,
dispatchTouchEvent()
uma vez que é difícil de controlar; às vezes, pode diminuir o desempenho. IMHO, sugiro substituironInterceptTouchEvent()
.Como a maioria das respostas menciona claramente o evento touch flow na atividade / exibição de grupo / exibição, apenas adiciono mais detalhes sobre o código desses métodos em
ViewGroup
(ignorandodispatchTouchEvent()
):onInterceptTouchEvent()
será chamado primeiro, o evento ACTION será chamado respectivamente para baixo -> mover -> para cima. Existem 2 casos:Se você retornar falso em três casos (ACTION_DOWN, ACTION_MOVE, ACTION_UP), ele considerará que os pais não precisarão desse evento de toque ; portanto,
onTouch()
os pais nuncaonTouch()
ligam , mas os filhos ligam ; no entanto, observe:onInterceptTouchEvent()
evento continua a receber toque, desde que seus filhos não liguemrequestDisallowInterceptTouchEvent(true)
.onTouch()
pais.Vice-versa, se você retornar verdadeiro , o pai roubará esse evento de toque imediatamente e
onInterceptTouchEvent()
parará imediatamente, em vezonTouch()
de os pais serem chamados e todos osonTouch()
filhos receberão o último evento de ação - ACTION_CANCEL (portanto, significa que os pais roubou um evento de toque e as crianças não podem lidar com isso a partir de então). O fluxo deonInterceptTouchEvent()
retorno false é normal, mas há um pouco de confusão com o retorno true case, então listo aqui:onTouch()
os pais receberão ACTION_DOWN novamente e após as ações (ACTION_MOVE, ACTION_UP).onTouch()
os pais receberão as próximas ACTION_MOVE (não são as mesmas ACTION_MOVEonInterceptTouchEvent()
) e as seguintes ações (ACTION_MOVE, ACTION_UP).onTouch()
os pais NÃO serão chamados, pois é muito tarde para os pais roubarem o evento de toque.Mais uma coisa importante é ACTION_DOWN do evento
onTouch()
, determinando se a visualização gostaria de receber mais ação desse evento ou não. Se a visualização retornar verdadeira em ACTION_DOWNonTouch()
, significa que a visualização está disposta a receber mais ações desse evento. Caso contrário, retornar false em ACTION_DOWN inonTouch()
implicará que a exibição não receberá mais nenhuma ação desse evento.fonte
Você pode encontrar a resposta neste vídeo https://www.youtube.com/watch?v=SYoN-OvdZ3M&list=PLonJJ3BVjZW6CtAMbJz1XD8ELUs1KXaTD&index=19 e nos próximos 3 vídeos. Todos os eventos de toque são explicados muito bem, é muito claro e cheio de exemplos.
fonte
O código a seguir em uma subclasse ViewGroup impediria que seus contêineres pai recebessem eventos de toque:
Usei isso com uma sobreposição personalizada para impedir que as visualizações em segundo plano respondam aos eventos de toque.
fonte
A principal diferença :
fonte
O ViewGroup's
onInterceptTouchEvent()
é sempre o ponto de entrada para oACTION_DOWN
evento que é o primeiro evento a ocorrer.Se você deseja que o ViewGroup processe esse gesto, retorne true de
onInterceptTouchEvent()
. Ao retornar true, o ViewGrouponTouchEvent()
receberá todos os eventos subsequentes até o próximoACTION_UP
ouACTION_CANCEL
, e na maioria dos casos, os eventos de toque entreACTION_DOWN
eACTION_UP
ouACTION_CANCEL
sãoACTION_MOVE
, que normalmente serão reconhecidos como gestos de rolagem / arremesso.Se você retornar false
onInterceptTouchEvent()
, as visões de destinoonTouchEvent()
serão chamadas. Ele será repetido para mensagens subseqüentes até que você retorne verdadeiroonInterceptTouchEvent()
.Fonte: http://neevek.net/posts/2013/10/13/implementing-onInterceptTouchEvent-and-onTouchEvent-for-ViewGroup.html
fonte
Activity e View têm o método dispatchTouchEvent () e onTouchEvent. O ViewGroup também possui esses métodos, mas possui outro método chamado onInterceptTouchEvent. O tipo de retorno desses métodos é booleano; você pode controlar a rota de despacho através do valor de retorno.
O envio do evento no Android inicia em Atividade-> Grupo de Visão-> Visão.
fonte
fonte
Pequena resposta:
onInterceptTouchEvent vem antes de setOnTouchListener.
fonte