Comment transmettre l'événement onClick d'une vue à son parent sur Android?

100

J'ai un TextView dans une mise en page dont l'arrière-plan est un sélecteur. Et le texte du TextView est défini sur Spanned from HTML. Ensuite, j'ai défini TextView avec LinkMovementMethod.

Désormais, lorsque je clique sur TextView, l'événement de clic n'est pas envoyé à sa disposition parente pour déclencher le sélecteur.

Comment résoudre ce problème?

Shiami
la source

Réponses:

45

Je pense que vous devez utiliser l'une de ces méthodes pour pouvoir intercepter l'événement avant qu'il ne soit envoyé aux composants appropriés:

Activity.dispatchTouchEvent(MotionEvent) - Cela permet à votre activité d'intercepter tous les événements tactiles avant qu'ils ne soient envoyés à la fenêtre.

ViewGroup.onInterceptTouchEvent(MotionEvent) - Cela permet à un ViewGroup de regarder les événements au fur et à mesure qu'ils sont distribués aux vues enfants.

ViewParent.requestDisallowInterceptTouchEvent(boolean) - Appelez ceci sur une vue parent pour indiquer qu'elle ne doit pas intercepter les événements tactiles avec onInterceptTouchEvent (MotionEvent).

Plus d'informations ici .

J'espère que cela pourra aider.

Luis Miguel Serrano
la source
1
Existe-t-il un moyen plus simple de transmettre les événements pour déclencher onClick et onLongClick dans la vue parent, ou je dois les implémenter moi-même?
shiami
Vérifiez ceci: stackoverflow.com/questions/2136696/pass-event-to-parent-view Vous voudrez peut-être essayer de transmettre le même écouteur de clic aux autres instances comme suggéré, même si je ne sais pas si cela fonctionnera , mais cela vaut peut-être la peine d'essayer.
Luis Miguel Serrano
La réponse ci-dessous est beaucoup plus propre
JPM
Dois-je instancier le MotionEvent? S'il vous plaît, expliquez, @LuisMiguelSerrano
olegario
@olegario, généralement vous redéfinissez la méthode par exemple pour dispatchTouchEvent, avec @Override, pour définir un nouveau comportement pour celui-ci, de sorte que vous ne recevez qu'un événement de mouvement que le système a fourni à votre activité (ou à un autre composant de votre application), et vous traitez-le et / ou transférez-le à n'importe quel nombre de composants enfants selon vos propres règles. Quelque chose comme: @Override public boolean dispatchTouchEvent(MotionEvent ev) { ... }
Luis Miguel Serrano
212

Déclarez votre TextViewnon cliquable / focalisable en utilisant android:clickable="false"et android:focusable="false"ou v.setClickable(false)et v.setFocusable(false). Les événements de clic doivent TextViewmaintenant être envoyés au parent de.

Remarque:

Pour y parvenir , vous devez ajouter un clic à son direct parent. ou set android:clickable="false"et android:focusable="false"à son parent direct pour transmettre l'auditeur à un autre parent .

siyb
la source
1
Oh mec si je pouvais donner ce +100 je le ferais. J'ai essayé de comprendre comment faire fonctionner un clic uniquement dans un ViewPager et non dans la disposition des adaptateurs avec TouchImageView implémentant onTouch! Cette solution a fonctionné comme un charme.
JPM
1
mais que faire si je veux gérer l'événement de changement de focus de EditText?
SweetWisher ツ
2
Le scénario est le suivant: j'ai une mise en page qui contient edittext, mise en page relative, spinner et vue de liste. Je veux déclencher un événement tactile de la mise en page parent chaque fois que je touche n'importe où sur l'écran, à l'exception de l'edittext et du spinner
SweetWisher ツ
9
Il est important de garder à l'esprit que si vous utilisez TextView#setOnClickListener()sur le TextView, il devient cliquable, même s'il est déclaré comme android:clickable="false", et même si le ClickListenerest réglé sur null( setOnclickListener(null))
Christian García
3
Fait amusant: si dans TextView il y a un android:inputTypeattribut, il consommera silencieusement les événements de clic même avec clickable: false & focusable: false; dans mon cas, il a été mis dans un style et il m'a fallu 30 minutes pour comprendre la cause.
Kirill Karmazin
18

Parfois, cela aide:

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

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

Une autre variante, ne fonctionne pas toujours:

child.setOnClickListener(null);
Alexandre Ukhov
la source
Cela a fonctionné pour CardViewla vue enfant, car CardViewsemble ignorer clickable="false"et focusable="false". Cependant, utiliser setOnTouchListeneret appeler onTouchEventle parent permet plutôt au parent d'afficher des commentaires tactiles (par exemple, un effet d'entraînement).
methodsignature
J'ai posté le code pertinent ci-dessous: stackoverflow.com/a/52928884/5652513 .
methodsignature
10

Mettre

android:duplicateParentState="true"

dans child alors les vues obtiennent son état dessinable (focalisé, pressé, etc.) de son parent direct plutôt que de lui-même. vous pouvez définir onclick pour parent et il appelle sur enfant cliqué

Ahmad Ronagh
la source
OP veut appeler l'écouteur de clic du parent lorsque l'enfant est cliqué, pas versa sage.
Farid
3

Si vous TextViewcréez des problèmes de clic, supprimez-le android:inputType=""de votre fichier xml.

Sanjay Chaudhary
la source
Si vous ne savez pas pourquoi, je vous recommande de ne pas le faire. Juste dire ... à chacun le sien.
dell116
Vous devriez le régler surandroid:inputType="none"
AZ_
1

Cette réponse est similaire à la réponse d'Alexander Ukhov , sauf qu'elle utilise des événements tactiles plutôt que des événements de clic. Ces événements permettent au parent d'afficher les états pressés appropriés (par exemple, effet d'entraînement). Cette réponse est également en Kotlin au lieu de Java.

view.setOnTouchListener { view, motionEvent ->
    (view.parent as View).onTouchEvent(motionEvent)
}
méthodes signature
la source
0

Si vous voulez à la fois OnTouchet OnClickauditeur vue parent et de l' enfant à la fois, s'il vous plaît utiliser ci - dessous astuce:

  1. User ScrollView en tant que vue parent et à l'intérieur qui a placé votre vue enfant dans Relative / LinearLayout.

  2. Faites en android:fillViewport="true"sorte que Parent ScrollView ne puisse pas faire défiler la vue

  3. Définissez ensuite l' OnTouchécouteur sur parent et l' OnClickécouteur sur les vues Enfant. Et profitez des deux rappels d'auditeur.

Kishor Patil
la source