Como passar um evento onClick de uma view para seu pai no Android?

100

Eu tenho um TextView em um layout cujo plano de fundo é um Seletor. E o texto do TextView é definido como Spanned from HTML. Então eu defino TextView com LinkMovementMethod.

Agora, quando toco em TextView, o evento de clique não é enviado ao layout pai para acionar o seletor.

Como isso deve ser resolvido?

Shiami
fonte

Respostas:

45

Acho que você precisa usar um desses métodos para poder interceptar o evento antes que ele seja enviado aos componentes apropriados:

Activity.dispatchTouchEvent(MotionEvent) - Isso permite que sua atividade intercepte todos os eventos de toque antes de serem despachados para a janela.

ViewGroup.onInterceptTouchEvent(MotionEvent) - Isso permite que um ViewGroup observe os eventos à medida que são despachados para as Views filhas.

ViewParent.requestDisallowInterceptTouchEvent(boolean) - Chame isso em uma Visualização pai para indicar que ela não deve interceptar eventos de toque com onInterceptTouchEvent (MotionEvent).

Mais informações aqui .

Espero que ajude.

Luis Miguel Serrano
fonte
1
Existe uma maneira mais fácil de passar os eventos para acionar onClick e onLongClick na visualização pai, ou eu mesmo tenho que implementá-los?
shiami
Verifique isto: stackoverflow.com/questions/2136696/pass-event-to-parent-view Possivelmente você pode querer tentar passar o mesmo ouvinte de clique para as outras instâncias, conforme sugerido, embora eu não saiba se funcionará , mas vale a pena tentar.
Luis Miguel Serrano
A resposta abaixo é muito mais
clara
Devo instanciar o MotionEvent? Por favor, explique, @LuisMiguelSerrano
olegario
@olegario, normalmente você redefine o método, por exemplo, para dispatchTouchEvent, com @Override, para definir um novo comportamento para ele, então você apenas recebe um evento de movimento que o sistema forneceu para sua atividade (ou outro componente de seu aplicativo), e você trate e / ou encaminhe para qualquer número de componentes filhos de acordo com suas próprias regras. Algo como: @Override public boolean dispatchTouchEvent(MotionEvent ev) { ... }
Luis Miguel Serrano
212

Declare que TextViewnão é clicável / focalizável usando android:clickable="false"e android:focusable="false"ou v.setClickable(false)e v.setFocusable(false). Os eventos de clique devem ser despachados para o TextViewpai de agora.

Nota:

Para conseguir isso , você deve adicionar clique ao seu direto parent. ou set android:clickable="false"e android:focusable="false"para seu pai direto para passar o ouvinte para outro pai .

siyb
fonte
1
Oh cara, se eu pudesse dar isso +100 eu daria. Estou tentando descobrir como fazer um clique funcionar apenas em um ViewPager e não no layout de adaptadores com TouchImageView implementando onTouch! Esta solução funcionou perfeitamente.
JPM
1
mas e se eu quiser controlar o evento de mudança de foco de EditText?
SweetWisher ツ
2
O cenário é: Eu tenho um layout que contém texto de edição, layout relativo, spinner e exibição de lista. Quero disparar o evento de toque do layout pai sempre que tocar em qualquer lugar da tela, exceto no texto de edição e no botão giratório
SweetWisher ツ
9
Algo importante a ter em mente é que se você usar TextView#setOnClickListener()no TextView, ele se tornará clicável, mesmo se declarado como android:clickable="false", e mesmo se o ClickListenerestiver definido como null( setOnclickListener(null))
Christian García
3
Curiosidade: se em TextView houver um android:inputTypeatributo, ele consumirá silenciosamente os eventos de clique, mesmo com clickable: false & focusable: false; no meu caso, foi definido em um estilo e me custou 30 minutos para descobrir a causa.
Kirill Karmazin de
18

Às vezes, apenas isso ajuda:

View child = parent.findViewById(R.id.btnMoreText);
    child.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            View parent = (View) v.getParent();
            parent.performClick();
        }
    });

Outra variante, nem sempre funciona:

child.setOnClickListener(null);
Alexander Ukhov
fonte
Isso funcionou CardViewcomo visão infantil, uma vez que CardViewparece ignorar clickable="false"e focusable="false". No entanto, usar setOnTouchListenere chamar onTouchEvento pai permite que ele exiba feedback de toque (por exemplo, efeito cascata).
assinatura do método
Postei o código relevante abaixo: stackoverflow.com/a/52928884/5652513 .
assinatura do método
10

Colocar

android:duplicateParentState="true"

na criança, as visualizações obtêm seu estado drawable (focalizado, pressionado etc.) de seu pai direto, e não de si mesmas. você pode definir onclick para o pai e chamar o filho clicado

Ahmad Ronagh
fonte
OP deseja chamar o ouvinte de clique dos pais quando o filho é clicado, e não vice-versa.
Farid
3

Se houver TextViewproblemas com o clique de criação, remova android:inputType=""-o do arquivo xml.

Sanjay Chaudhary
fonte
Se você não sabe por quê, recomendo que não faça isso. Apenas dizendo ... a cada um o seu.
dell116
Você deve defini-lo comoandroid:inputType="none"
AZ_
1

Essa resposta é semelhante à resposta de Alexander Ukhov , exceto que usa eventos de toque em vez de eventos de clique. Esses eventos permitem que o pai exiba os estados pressionados apropriados (por exemplo, efeito cascata). Essa resposta também está em Kotlin em vez de Java.

view.setOnTouchListener { view, motionEvent ->
    (view.parent as View).onTouchEvent(motionEvent)
}
assinatura de método
fonte
0

Se você quer tanto OnTouche OnClickouvinte para pais e filhos vista tanto, utilize o abaixo truque:

  1. O usuário ScrollView como uma visão pai e dentro dela colocou a visão filho dentro de Relative / LinearLayout.

  2. Faça o Parent ScrollView android:fillViewport="true"para que a visualização não seja rolada.

  3. Em seguida, defina OnTouchlistener como pai e OnClicklistener como visualizações Filha. E aproveite os dois retornos de chamada do ouvinte.

Kishor Patil
fonte