J'explorais RecyclerView
et j'ai été surpris de voir que cela RecyclerView
n'a pas onItemClickListener()
.
J'ai deux questions.
Question principale
Je veux savoir pourquoi Google a supprimé onItemClickListener()
?
Y a-t-il un problème de performances ou autre chose?
Question secondaire
J'ai résolu mon problème en écrivant onClick
dans mon RecyclerView.Adapter
:
public static class ViewHolder extends RecyclerView.ViewHolder implements OnClickListener {
public TextView txtViewTitle;
public ImageView imgViewIcon;
public ViewHolder(View itemLayoutView) {
super(itemLayoutView);
txtViewTitle = (TextView) itemLayoutView.findViewById(R.id.item_title);
imgViewIcon = (ImageView) itemLayoutView.findViewById(R.id.item_icon);
}
@Override
public void onClick(View v) {
}
}
Est-ce correct / existe-t-il une meilleure façon?
java
android
android-recyclerview
Tarun Varshney
la source
la source
QUESTION
Réponses:
tl; dr 2016 Utilisez RxJava et un PublishSubject pour exposer un observable pour les clics.
Message d'origine:
Depuis l'introduction de
ListView
,onItemClickListener
a été problématique. Au moment où vous avez un écouteur de clics pour l'un des éléments internes, le rappel ne sera pas déclenché, mais il n'a pas été notifié ou bien documenté (le cas échéant), il y avait donc beaucoup de confusion et de SO questions à ce sujet.Étant donné que
RecyclerView
cela va un peu plus loin et n'a pas de concept de ligne / colonne, mais plutôt un nombre arbitrairement disposé d'enfants, ils ont délégué le onClick à chacun d'eux, ou à la mise en œuvre du programmeur.Recyclerview
Ne pensez pas comme unListView
remplacement 1: 1 mais plutôt comme un composant plus flexible pour les cas d'utilisation complexes. Et comme vous le dites, votre solution est ce que Google attend de vous. Vous avez maintenant un adaptateur qui peut déléguer onClick à une interface transmise au constructeur, qui est le modèle correct pourListView
etRecyclerview
.puis sur votre adaptateur
Examinez maintenant ce dernier morceau de code:
onCreateViewHolder(ViewGroup parent, int viewType)
la signature suggère déjà différents types de vue. Pour chacun d'eux, vous aurez également besoin d'un viewholder différent, et par la suite chacun d'eux peut avoir un ensemble de clics différent. Ou vous pouvez simplement créer une vue générique qui prend n'importe quelle vue et uneonClickListener
et s'applique en conséquence. Ou déléguez un niveau à l'orchestrateur afin que plusieurs fragments / activités aient la même liste avec un comportement de clic différent. Encore une fois, toute flexibilité est de votre côté.C'est un composant vraiment nécessaire et assez proche de ce qu'étaient nos implémentations et améliorations internes
ListView
jusqu'à présent. C'est bien que Google le reconnaisse enfin.la source
onBindViewHolder(holder, position)
, qui est l'endroit où les informations sont censées être remplies.getPosition()
est obsolète "Cette méthode est obsolète car sa signification est ambiguë en raison de la gestion asynchrone * des mises à jour de l'adaptateur. Veuillez utiliser {@link #getLayoutPosition ()} ou * {@link #getAdapterPosition ()} selon votre cas d'utilisation. "viewHolder.getPosition();
Pourquoi le RecyclerView n'a pas
onItemClickListener
C'est
RecyclerView
une boîte à outils, contrairement à l'ancienne,ListView
elle a moins de fonctionnalités et plus de flexibilité. CeonItemClickListener
n'est pas la seule fonctionnalité supprimée de ListView. Mais il a beaucoup d'auditeurs et de méthode pour l'étendre à votre guise, il est bien plus puissant entre de bonnes mains;).À mon avis, la fonctionnalité la plus complexe supprimée
RecyclerView
est le Fast Scroll . La plupart des autres fonctionnalités peuvent être facilement réimplémentées.Si vous voulez savoir quelles autres fonctionnalités intéressantes
RecyclerView
ajoutées, lisez cette réponse à une autre question.Efficace en mémoire - solution intégrée pour onItemClickListener
Cette solution a été proposée par Hugo Visser , un Android GDE, juste après
RecyclerView
sa sortie. Il a mis à votre disposition une classe sans licence pour simplement déposer votre code et l'utiliser.Il met en valeur une partie de la polyvalence introduite avec
RecyclerView
en faisant usage deRecyclerView.OnChildAttachStateChangeListener
.Edit 2019 : version kotlin par moi, java one, de Hugo Visser, gardée ci-dessous
Kotlin / Java
Créez un fichier
values/ids.xml
et mettez-le dedans:puis ajoutez le code ci-dessous à votre source
Kotlin
Usage:
(il prend également en charge les longs clics sur les objets et voir ci-dessous pour une autre fonctionnalité que j'ai ajoutée).
implémentation (mon adaptation au code Java de Hugo Visser):
(voir ci-dessous, vous devez également ajouter un fichier XML)
Fonction bonus de la version Kotlin
Parfois, vous ne voulez pas que tous les éléments de RecyclerView soient cliquables.
Pour gérer cela, j'ai introduit l'
ItemClickSupportViewHolder
interface que vous pouvez utiliser sur votreViewHolder
pour contrôler quel élément est cliquable.Exemple:
Java
Usage:
(il prend également en charge le clic long sur un élément)
Mise en œuvre (commentaires ajoutés par moi):
Comment ça marche (pourquoi c'est efficace)
Cette classe fonctionne en attachant un
RecyclerView.OnChildAttachStateChangeListener
auRecyclerView
. Cet écouteur est averti chaque fois qu'un enfant est attaché ou détaché duRecyclerView
. Le code l'utilise pour ajouter un écouteur tap / long click à la vue. Cet auditeur demande leRecyclerView
pourRecyclerView.ViewHolder
qui contient la position.C'est plus efficace que les autres solutions car cela évite de créer plusieurs écouteurs pour chaque vue et continue de les détruire et de les créer pendant le
RecyclerView
défilement.Vous pouvez également adapter le code pour vous rendre le support lui-même si vous en avez besoin de plus.
Remarque finale
Gardez à l'esprit qu'il est COMPLÈTEMENT bien de le gérer dans votre adaptateur en définissant sur chaque vue de votre liste un écouteur de clic, comme les autres réponses proposées.
Ce n'est tout simplement pas la chose la plus efficace à faire (vous créez un nouvel écouteur chaque fois que vous réutilisez une vue) mais cela fonctionne et dans la plupart des cas, ce n'est pas un problème.
C'est également un peu contre la séparation des préoccupations car ce n'est pas vraiment le travail de l'adaptateur de déléguer les événements de clic.
la source
addTo()
etremoveFrom()
. L'instance est associée à la balise recyclerview et meurt avec elle ou lorsqu'elle est supprimée manuellement.onCreateViewHolder
et c'est tout.RecyclerView
.J'aime cette façon et je l'utilise
À l'intérieur
Mettre
Et créez cette classe où vous le voulez
J'ai déjà lu qu'il y avait une meilleure façon mais j'aime que cette façon soit facile et pas compliquée.
la source
MyOnClickListener
devenir une variable d'instance, car vous ennew
recyclerView
dans MyOnClickListener?Android Recyclerview With
onItemClickListener
, Why we cant try this works like likeListView
only.Source: Lien
Et définissez ceci sur RecyclerView:
la source
SwipeRefreshLayout
Grâce à @marmor, j'ai mis à jour ma réponse.
Je pense que c'est une bonne solution pour gérer le onClick () dans le constructeur de la classe ViewHolder et le transmettre à la classe parente via l' interface OnItemClickListener .
MyAdapter.java
Utilisation de l'adaptateur dans d'autres classes:
MyFragment.java
la source
onBindViewHolder()
appelé plusieurs fois pour la même vue lors du défilement. Même la création d'un singleOnClickListener
n'aidera pas car vous serez réinitialisé àOnClickListener
chaqueonBindViewHolder()
appel. Voir plutôt la solution @ MLProgrammer-CiM.MyAdapter.ViewHolder vh = new ViewHolder(v, new MyAdapter.ViewHolder.IMyViewHolderClicks() ....
vous pouvez créer un écouteur unique pour toutes les vues.Les gars utilisent ce code dans votre activité principale. Méthode très efficace
Voici votre classe d'adaptateur.
Après cela, vous obtiendrez cette méthode de remplacement dans votre activité.
la source
> En quoi RecyclerView est-il différent de Listview?
Une différence est qu'il ya
LayoutManager
classe avec RecyclerView par lequel vous pouvez gérer votreRecyclerView
comme-Comme pour le défilement horizontal pour RecyclerView-
la source
Faisant suite une excellente solution RxJava de MLProgrammer-CiM
Consommer / observer les clics
RxJava 2. +
Modifiez le tl; dr d'origine comme:
PublishSubject#asObservable()
a été éliminé. Il suffit de retourner lePublishSubject
qui est unObservable
.la source
Comment mettre tout cela ensemble exemple ...
Types de ViewHolder
la source
Pour autant que je comprends la réponse MLProgrammer-CiM , il est simplement possible de le faire:
la source
Après avoir lu la réponse de @ MLProgrammer-CiM , voici mon code:
la source
getAdapterPosition
peut revenir-1
pour "aucune position".J'ai fait de cette façon, c'est très simple:
Ajoutez simplement 1 ligne pour la position Clicker RecyclerView :
Code complet pour la classe ViewHolder :
J'espère que cela vous aidera.
la source
getAdapterPosition
place degetLayoutPosition
. Protégez-vous-1
.J'utilise cette méthode pour démarrer une intention à partir de RecyclerView:
la source
onBindViewHolder(...)
n'est pas appelé après lesnotify()
méthodes. Ainsi, vous pouvez obtenir une position de clic incorrecte dans certaines situations.RecyclerView n'en a pas
onItemClickListener
car RecyclerView est responsable du recyclage des vues (surprise!), C'est donc la responsabilité de la vue qui est recyclée de gérer les événements de clic qu'elle reçoit.Cela rend en fait beaucoup plus facile à utiliser, surtout si vous aviez des éléments sur lesquels vous pouvez cliquer à plusieurs endroits.
Quoi qu'il en soit, la détection d'un clic sur un élément RecyclerView est très simple. Il vous suffit de définir une interface (si vous n'utilisez pas Kotlin, auquel cas vous passez juste un lambda):
Même code dans Kotlin:
Ce que vous n'avez PAS besoin de faire:
1.) vous n'avez pas besoin d'intercepter manuellement les événements tactiles
2.) vous n'avez pas besoin de jouer avec les auditeurs de changement d'état
3.) vous n'avez pas besoin de PublishSubject / PublishRelay de RxJava
Utilisez simplement un écouteur de clics.
la source
Voir mon approche à ce sujet:
Déclarez d'abord une interface comme celle-ci:
Créez ensuite l'adaptateur:
Et maintenant, voyons comment intégrer cela à partir d'un fragment:
la source
Si vous souhaitez ajouter onClick () à la vue enfant des éléments, par exemple, un bouton dans l'élément, j'ai constaté que vous pouvez le faire facilement dans onCreateViewHolder () de votre propre RecyclerView.Adapter comme ceci:
je ne sais pas si c'est un bon moyen, mais ça marche bien. Si quelqu'un a une meilleure idée, très heureux de me le dire et de corriger ma réponse! :)
la source
Voici un moyen de l'implémenter assez facilement si vous avez une liste de POJO et que vous souhaitez en récupérer un en un clic depuis l'extérieur de l'adaptateur.
Dans votre adaptateur, créez un écouteur pour les événements de clic et une méthode pour le définir:
}
Dans votre ViewHolder, implémentez onClickListener et créez un membre de classe pour stocker temporairement le POJO que la vue présente, de cette façon (c'est un exemple, créer un setter serait mieux):
De retour dans votre adaptateur, définissez le POJO actuel lorsque le ViewHolder est lié (ou à null si la vue actuelle n'en a pas):
Voilà, maintenant vous pouvez l'utiliser comme ceci à partir de votre fragment / activité:
la source
mMyAdapter.setOnItemClickListener(MyAdapter.OnItemClickListener() {});
Oui, vous pouvez
la source
Ici, vous pouvez gérer plusieurs onclick voir le code ci-dessous et il est très efficace
la source
itemView
.Modifié mon commentaire ...
la source
getAdapterPosition()
.Vérifiez celui-ci dans lequel j'ai mis en œuvre toutes les choses d'une manière appropriée
Classe RecyclerViewHolder
Adaptateur
L'interface
la source
Cela a fonctionné pour moi:
la source
setOnClickListener(holder)
àonBindViewHolder()
. Parce que onBindViewHolder (...) n'est pas appelé après les méthodes notify (). Ainsi, vous pouvez obtenir une position de clic incorrecte dans certaines situations.onCreateViewHolder
.Accédez au
mainView
derowLayout(cell)
vousRecyclerView
et dans votreOnBindViewHolder
écriture ce code:la source
Au lieu d'implémenter l'interface View.OnClickListener à l'intérieur du support de vue ou de créer et d'interfacer et d'implémenter une interface dans votre activité .. J'ai utilisé ce code pour la mise en œuvre d'OnClickListener.
la source
Porte-vue intérieure
Dans OnBindViewHolder ()
Et faites-moi savoir, avez-vous des questions sur cette solution?
la source
onCreateViewHolder
pour de meilleures performances, mais vous devez ensuite obtenir la position en utilisantgetAdapterPosition()
(et en-1
la source
utiliser PlaceHolderView
la source
J'ai écrit une bibliothèque pour gérer l'événement de clic d'élément d'affichage du recycleur Android. Vous pouvez trouver un didacticiel complet sur https://github.com/ChathuraHettiarachchi/RecycleClick
ou pour manipuler un élément, appuyez longuement sur, vous pouvez utiliser
la source
l'animation recyclerview n'a pas été testée, l'autre est normale. Je pense qu'il a été optimisé au maximum. L'interface a d'autres utilisations, vous pouvez temporairement l'ignorer.
Ceci est l'interface
Ceci est une classe abstraite
Vous n'en avez besoin que
la source
Exemple avec getTag () / setTag () et écouteur à simple clic pour l'adaptateur entier:
La TAG_POSITION définie dans le fichier tags.xml comme
la source