En gros, j'aimerais associer un seul OnClickListener à plusieurs vues à l'intérieur d'un ConstraintLayout.
Avant de migrer vers ConstraintLayout, les vues se trouvaient à l’intérieur d’une disposition sur laquelle je pouvais ajouter un écouteur. Ils se trouvent maintenant sur le même calque que d'autres vues, juste sous ConstraintLayout.
J'ai essayé d'ajouter les vues à un Android.support.constraint.Group
et de lui ajouter un OnClickListener par programme.
group.setOnClickListener {
Log.d("OnClick", "groupClickListener triggered")
}
Cependant, cela ne semble pas fonctionner à partir de la version 1.1.0-beta2
de ConstraintLayout
Ai-je commis une erreur, existe-t-il un moyen de résoudre ce problème ou dois-je associer l'auditeur à chacune des vues?
La Group
dans ConstraintLayout
est simplement une association lâche de vues, autant que je sache. Ce n'est pas une ViewGroup
, vous ne pourrez donc pas utiliser un écouteur en un seul clic comme vous le faisiez lorsque les vues étaient dans une ViewGroup
.
Au lieu de cela, vous pouvez obtenir une liste des identifiants membres de votre Group
dans votre code et définir explicitement l'écouteur de clics. (Je n'ai pas trouvé de documentation officielle sur cette fonctionnalité, mais je pense qu'elle est juste en retard sur la publication du code.) Voir la documentation sur getReferencedIds
ici .
Java:
Group group = findViewById(R.id.group);
int refIds[] = group.getReferencedIds();
for (int id : refIds) {
findViewById(id).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// your code here.
}
});
}
Dans Kotlin, vous pouvez créer une fonction d’extension pour cela.
Kotlin:
fun Group.setAllOnClickListener(listener: View.OnClickListener?) {
referencedIds.forEach { id ->
rootView.findViewById<View>(id).setOnClickListener(listener)
}
}
Ensuite, appelez la fonction du groupe:
group.setAllOnClickListener(View.OnClickListener {
// code to perform on click event
})
Pour compléter la réponse acceptée pour Kotlin, les utilisateurs créent une fonction d’extension et acceptent un lambda qui ressemble davantage à l’API group.addOnClickListener { }
.
fun Group.addOnClickListener(listener: (view: View) -> Unit) {
referencedIds.forEach { id ->
rootView.findViewById<View>(id).setOnClickListener(listener)
}
}
group.addOnClickListener { v ->
Log.d("GroupExt", v)
}
Le meilleur moyen d'écouter les événements de clic provenant de plusieurs vues consiste à ajouter une vue transparente en tant que conteneur au-dessus de toutes les vues requises. Cette vue doit être à la fin (c'est-à-dire en haut) de toutes les vues sur lesquelles vous devez cliquer.
Exemple de vue du conteneur:
<View
Android:id="@+id/view_container"
Android:layout_width="0dp"
Android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="@+id/view_bottom"
app:layout_constraintEnd_toEndOf="@+id/end_view_guideline"
app:layout_constraintStart_toStartOf="@+id/start_view_guideline"
app:layout_constraintTop_toTopOf="parent"/>
L'exemple ci-dessus contient les quatre limites de contrainte, vous pouvez ajouter des vues à écouter ensemble. Comme c'est une vue, vous pouvez faire ce que vous voulez, comme un effet d'entraînement.
Bien que j'apprécie l'approche générale de la { réponse de Vitthalk }, _ _ je pense qu'elle présente un inconvénient majeur et deux inconvénients mineurs.
Il ne prend pas en compte les changements de position dynamiques des vues uniques
Il peut enregistrer des clics pour des vues qui ne font pas partie du groupe.
Bien que je ne sois pas sûr de trouver une solution au deuxième point, il existe clairement des points faciles pour le premier et le troisième.
1. Modifications de la position comptable de l'élément dans le groupe
C'est en fait assez simple. Vous pouvez utiliser le jeu d’outils de la disposition des contraintes pour ajuster les bords de la vue transparente . Nous utilisons simplement Barrières pour recevoir les positions les plus à gauche, les plus à droite, etc. de toute vue du groupe . Ensuite, nous pouvons ajuster la vue transparente aux barrières au lieu des vues concrètes.
3. Solution générique
En utilisant Kotlin, nous pouvons étendre la classe de groupe pour inclure une méthode qui ajoute un ClickListener à une vue, comme décrit ci-dessus . aligné sur les barrières et enregistre le ClickListener dans le dernier.
De cette façon, nous devons simplement appeler la méthode sur le groupe et ne pas avoir besoin d'ajouter les vues à la présentation manuellement à chaque fois que nous avons besoin de ce comportement.
La méthode d’extension est excellente mais vous pouvez la rendre encore meilleure en la changeant en
fun Group.setAllOnClickListener(listener: (View) -> Unit) {
referencedIds.forEach { id ->
rootView.findViewById<View>(id).setOnClickListener(listener)
}
}
Donc, l'appel serait comme ça
group.setAllOnClickListener {
// code to perform on click event
}
Désormais, il n'est plus nécessaire de définir explicitement View.OnClickListener.
Vous pouvez également définir votre propre interface pour GroupOnClickLitener comme ceci
interface GroupOnClickListener {
fun onClick(group: Group)
}
puis définir une méthode d'extension comme celle-ci
fun Group.setAllOnClickListener(listener: GroupOnClickListener) {
referencedIds.forEach { id ->
rootView.findViewById<View>(id).setOnClickListener { listener.onClick(this)}
}
}
et l'utiliser comme ça
groupOne.setAllOnClickListener(this)
groupTwo.setAllOnClickListener(this)
groupThree.setAllOnClickListener(this)
override fun onClick(group: Group) {
when(group.id){
R.id.group1 -> //code for group1
R.id.group2 -> //code for group2
R.id.group3 -> //code for group3
else -> throw IllegalArgumentException("wrong group id")
}
}
La deuxième approche offre de meilleures performances si le nombre de vues est grand, car vous n'utilisez qu'un seul objet comme écouteur pour toutes les vues!