Comment actualiser les données affichées dans RecyclerView
(en appelant notifyDataSetChanged
son adaptateur) et s'assurer que la position de défilement est réinitialisée exactement là où elle était?
En cas de bon vieux, ListView
il suffit de récupérer getChildAt(0)
, de vérifier getTop()
et d'appeler setSelectionFromTop
avec les mêmes données exactes par la suite.
Cela ne semble pas possible en cas de RecyclerView
.
Je suppose que je suis censé utiliser son LayoutManager
qui fournit en effet scrollToPositionWithOffset(int position, int offset)
, mais quelle est la bonne façon de récupérer la position et le décalage?
layoutManager.findFirstVisibleItemPosition()
et layoutManager.getChildAt(0).getTop()
?
Ou y a-t-il une manière plus élégante de faire le travail?
la source
Réponses:
J'utilise celui-ci. ^ _ ^
C'est plus simple, j'espère que cela vous aidera!
la source
J'ai un problème assez similaire. Et j'ai trouvé la solution suivante.
L'utilisation
notifyDataSetChanged
est une mauvaise idée. Vous devriez être plus précis, puisRecyclerView
enregistrera l'état de défilement pour vous.Par exemple, si vous avez seulement besoin d'actualiser, ou en d'autres termes, vous voulez que chaque vue soit reliée, procédez comme suit:
la source
notifyDataSetChanged
train d' insérer plusieurs éléments à la position 0 et avec la position de défilement changerait montrant les nouveaux éléments. Cependant, si vous utiliseznotifyItemRangeInserted(0, newItems.size() - 1)
le,RecyclerView
conserve l'état de défilement.EDIT: Pour restaurer exactement la même position apparente , comme dans, la faire ressembler exactement à ce qu'elle était, nous devons faire quelque chose d'un peu différent (voir ci-dessous comment restaurer la valeur exacte scrollY):
Enregistrez la position et le décalage comme ceci:
Et puis restaurez le parchemin comme ceci:
Cela rétablit la liste à sa position apparente exacte . Apparent car il aura le même aspect pour l'utilisateur, mais il n'aura pas la même valeur scrollY (en raison des différences possibles dans les dimensions de la mise en page paysage / portrait).
Notez que cela ne fonctionne qu'avec LinearLayoutManager.
--- Ci-dessous comment restaurer le scrollY exact, ce qui rendra probablement la liste différente ---
Appliquez un OnScrollListener comme ceci:
Cela stockera la position de défilement exacte à tout moment dans mScrollY.
Stockez cette variable dans votre Bundle et restaurez-la dans la restauration de l'état vers une variable différente , nous l'appellerons mStateScrollY.
Après la restauration de l'état et après que votre RecyclerView a réinitialisé toutes ses données, réinitialisez le défilement avec ceci:
C'est tout.
Attention, vous restaurez le scroll vers une variable différente, c'est important, car le OnScrollListener sera appelé avec .scrollBy () et par la suite affectera mScrollY à la valeur stockée dans mStateScrollY. Si vous ne le faites pas, mScrollY aura le double de la valeur de défilement (car OnScrollListener fonctionne avec des deltas, pas des défilements absolus).
L'économie d'état dans les activités peut être réalisée comme ceci:
Et pour restaurer, appelez ceci dans votre onCreate ():
La sauvegarde d'état dans les fragments fonctionne de la même manière, mais la sauvegarde d'état réelle nécessite un peu de travail supplémentaire, mais il y a beaucoup d'articles traitant de cela, vous ne devriez donc pas avoir de problème pour savoir comment, les principes de sauvegarde du parcheminY et le restaurer restent les mêmes.
la source
Oui, vous pouvez résoudre ce problème en créant le constructeur de l'adaptateur une seule fois, j'explique la partie de codage ici:
Vous pouvez maintenant voir que j'ai vérifié que l'adaptateur est nul ou non et que je ne l'initialise que lorsqu'il est nul.
Si l'adaptateur n'est pas nul, je suis assuré que j'ai initialisé mon adaptateur au moins une fois.
Je vais donc simplement ajouter la liste à l'adaptateur et appeler notifydatasetchanged.
RecyclerView maintient toujours la dernière position défilée, vous n'avez donc pas à stocker la dernière position, appelez simplement notifydatasetchanged, la vue recycleur actualise toujours les données sans aller en haut.
Merci Happy Coding
la source
Gardez la position de défilement en utilisant la réponse @DawnYu pour envelopper
notifyDataSetChanged()
comme ceci:la source
La première réponse de @DawnYu fonctionne, mais la vue de recyclage défilera d'abord vers le haut, puis retournera à la position de défilement voulue, provoquant une réaction de type «scintillement» qui n'est pas agréable.
Pour actualiser recyclerView, en particulier après être issu d'une autre activité, sans scintillement et en conservant la position de défilement, vous devez effectuer les opérations suivantes.
J'espère que cela t'aides.
la source
Je n'ai pas utilisé Recyclerview mais je l'ai fait sur ListView. Exemple de code dans Recyclerview:
C'est l'auditeur lorsque l'utilisateur fait défiler. La surcharge de performance n'est pas significative. Et la première position visible est précise de cette façon.
la source
findFirstVisibleItemPosition
renvoie "la position de l'adaptateur de la première vue visible", mais qu'en est-il du décalage.La solution ici est de continuer à faire défiler la vue de recyclage lorsqu'un nouveau message arrive.
La méthode onChanged () détecte l'action effectuée sur recyclerview.
la source
Cela fonctionne pour moi à Kotlin.
Le décalage de défilement ne change pas.
la source
J'ai eu ce problème avec une liste d'articles qui avaient chacun un temps en minutes jusqu'à ce qu'ils soient «dus» et avaient besoin d'être mis à jour. Je mettrais à jour les données et ensuite, j'appellerais
et il défilerait vers le haut à chaque fois. Je l'ai remplacé par
et c'était bien. Aucune des autres méthodes de ce fil n'a fonctionné pour moi. Cependant, en utilisant cette méthode, chaque élément individuel a clignoté lors de sa mise à jour, je devais donc également le mettre dans onCreateView du fragment parent.
la source
Si vous avez un ou plusieurs EditTexts à l'intérieur des éléments d'un recyclerview, désactivez l'autofocus de ceux-ci, en plaçant cette configuration dans la vue parente de recyclerview:
J'ai eu ce problème lorsque j'ai commencé une autre activité lancée à partir d'un élément recyclerview, lorsque je suis revenu et j'ai défini une mise à jour d'un champ dans un élément avec notifyItemChanged (position) le défilement des mouvements de RV, et ma conclusion était que, l'autofocus d'EditText Articles, le code ci-dessus a résolu mon problème.
meilleur.
la source
Renvoyez simplement si l'ancienne position et la position sont identiques;
la source