Obtenez des éléments visibles dans RecyclerView


Réponses:


579

Le premier / dernier enfant visible dépend du LayoutManager. Si vous utilisez LinearLayoutManagerou GridLayoutManager, vous pouvez utiliser

int findFirstVisibleItemPosition();
int findFirstCompletelyVisibleItemPosition();
int findLastVisibleItemPosition();
int findLastCompletelyVisibleItemPosition();

Par exemple:

GridLayoutManager layoutManager = ((GridLayoutManager)mRecyclerView.getLayoutManager());
int firstVisiblePosition = layoutManager.findFirstVisibleItemPosition();

Pour LinearLayoutManager, le premier / dernier dépend de la commande de l'adaptateur. Ne pas interroger les enfants de RecyclerView; LayoutManagerpeut préférer mettre en page plus d'éléments que visibles pour la mise en cache.


10
Existe-t-il une possibilité d'accéder à ces méthodes à partir de RecyclerView.Adapter sans passer de référence à LayoutManager?
Yorgi

3
Comme @Yorgi - à l'intérieur de l'adaptateur semble utile. Je me demande s'il y a un modèle que vous pouvez développer en utilisant onBindViewHolder pour suivre ceux qui sont réellement à l'écran pendant qu'un utilisateur défile.
RoundSparrow hilltx

7
getItemCountpeut renvoyer 1 et findFirstVisibleItemPosition-1 sur le même appel.
mbmc

4
que pouvez-vous suggérer à propos de StaggeredLayoutManager?
hornet2319

37
Ces méthodes sont si peu fiables qu'elles sont totalement inutiles. Surtout après notifyDataSetChanged / itemRemoved / RangeChanged
JK

12

Enfin, j'ai trouvé une solution pour savoir si l'élément actuel est visible, à partir de l'événement onBindViewHolder dans l'adaptateur.

La clé est la méthode isViewPartiallyVisible de LayoutManager.

Dans votre adaptateur, vous pouvez obtenir le LayoutManager à partir de RecyclerView, que vous obtenez comme paramètre à partir du événement onAttachedToRecyclerView .


Mais où appelleriez-vous cette méthode dans laquelle le gestionnaire de disposition n'est pas nul?
6rchid

Vous devez attendre l'événement onAttachedToRecyclerView de l'adaptateur. Dans ce cas, vous recevez le RecyclerView en tant que paramètre; puis vous pouvez obtenir le LayoutManager à partir de RecyclerVie et l'enregistrer dans une variable globale. Si le LayoutManager est nul, cela pourrait probablement être dû au fait qu'il n'a pas été affecté à RecyclerView dans Activity / Fragment / Layout; et essayez de créer l'adaptateur après cette affectation.
Ernesto Vega

Selon le code source, isViewPartiallyVisible est gravement endommagé. Si complètementVisible est vrai, il retournera vrai si la vue est entièrement visible. Cependant, s'il est faux, il annule simplement le résultat qui retourne vrai si la vue est partiellement visible ou non visible. Même la documentation n'a pas de sens.
Molanda


9

pour ceux qui ont une logique à implémenter à l'intérieur de l'adaptateur RecyclerView, vous pouvez toujours utiliser l'approche @ernesto combinée avec un scrollListener pour obtenir what you wantlorsque le RecyclerView est consulté. À l'intérieur de l'adaptateur, vous aurez quelque chose comme ceci:

@Override
    public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);
        RecyclerView.LayoutManager manager = recyclerView.getLayoutManager();
        if(manager instanceof LinearLayoutManager && getItemCount() > 0) {
            LinearLayoutManager llm = (LinearLayoutManager) manager;
            recyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
                @Override
                public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
                    super.onScrollStateChanged(recyclerView, newState);
                }

                @Override
                public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
                    super.onScrolled(recyclerView, dx, dy);
                        int visiblePosition = llm.findFirstCompletelyVisibleItemPosition();
                        if(visiblePosition > -1) {
                            View v = llm.findViewByPosition(visiblePosition);
                            //do something
                            v.setBackgroundColor(Color.parseColor("#777777"));
                        }
                }
            });
        }
    }

7

Vous pouvez utiliser recyclerView.getChildAt()pour obtenir chaque enfant visible, et définir une balise convertview.setTag(index)sur cette vue dans le code de l'adaptateur vous aidera à le relier aux données de l'adaptateur.


Le problème avec getChildAt () est que l'ordre des éléments peut être parmi 5 éléments: 0, 5, 4, 3, 2, 1 (le nombre d'enfants est principalement> = le nombre d'éléments visibles). J'ai donc essayé d'obtenir l'ordre de l'élément via getGlobalVisibleRect.
rekire

Quelle est votre exigence réelle, obtenir un enfant visible (enfant à l'intérieur de l'écran lié) dans l'ordre réel?
Sreejith B Naick

Maintenant je veux savoir quel élément est au centre, plus tard je m'intéresse peut-être aussi aux limites.
rekire

1
Vous n'obtiendrez que des éléments visibles recyclerView.getChildAt(), c'est ainsi que cela RecyclerViewfonctionne généralement . RecyclerViewessaiera de ne conserver que quelques vues enfant qui sont actuellement visibles (c'est-à-dire dans les limites de l'écran, pas la visibilité en tant que disparu, INVISIBLE) et essaiera de recycler ces vues lorsque l'utilisateur défile.
Sreejith B Naick

6
Afficher visibleChild = recyclerView.getChildAt (0); int positionOfChild = recyclerView.getChildAdapterPosition (visibleChild);
Kevin Lee

5

Addendum :

Les fonctions proposées findLast ... Position () ne fonctionnent pas correctement dans un scénario avec une barre d'outils repliée pendant que la barre d'outils est développée.

Il semble que la vue du recycleur ait une hauteur fixe, et tandis que la barre d'outils est développée, le recycleur est déplacé vers le bas, partiellement hors de l'écran. En conséquence, les résultats des fonctions proposées sont trop élevés. Exemple: le dernier élément visible est dit # 9, mais en fait, l'élément # 7 est le dernier qui est à l'écran.

Ce comportement est également la raison pour laquelle ma vue échouait souvent à la position correcte, c'est-à-dire que scrollToPosition () ne fonctionnait pas correctement (j'ai finalement réduit la barre d'outils par programme).


C'est vrai, mais c'est ainsi que fonctionne la barre d'outils de réduction. J'ai arrêté de développer des applications Android il y a un an, mais je m'en souviens.
rekire

4

Les Linear / Grid LayoutManagerméthodes suivantes peuvent être utilisées pour vérifier quels éléments sontvisible

int findFirstVisibleItemPosition();
int findLastVisibleItemPosition();
int findFirstCompletelyVisibleItemPosition();
int findLastCompletelyVisibleItemPosition();

et si vous souhaitez suivre is item visible on screenun certain seuil, vous pouvez vous référer au blog suivant.

https://proandroiddev.com/detecting-list-items-perceived-by-user-8f164dfb1d05


3

Pour StaggeredGridLayoutManagercela:

RecyclerView rv = findViewById(...);
StaggeredGridLayoutManager lm = new StaggeredGridLayoutManager(...);
rv.setLayoutManager(lm);

Et pour obtenir des vues d'objets visibles:

int[] viewsIds = lm.findFirstCompletelyVisibleItemPositions(null);
ViewHolder firstViewHolder = rvPlantios.findViewHolderForLayoutPosition(viewsIds[0]);
View itemView = viewHolder.itemView;

N'oubliez pas de vérifier s'il est vide.


Que voulez-vous dire "vérifier s'il est vide"? Comment vérifie-t-on?
tmm1

viewsIdsest un tableau, et il peut être vide.
Douglas Nassif Roma Junior
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.