Obter itens visíveis no RecyclerView

Respostas:

579

O primeiro / último filho visível depende do LayoutManager. Se você estiver usando LinearLayoutManagerou GridLayoutManager, poderá usar

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

Por exemplo:

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

Pois LinearLayoutManager, o primeiro / o último depende da ordem do adaptador. Não consulte filhos de RecyclerView; LayoutManagerpode preferir o layout de mais itens do que o visível para o cache.

yigit
fonte
10
Existe alguma possibilidade de acessar esses métodos no RecyclerView.Adapter sem passar referência ao LayoutManager?
Yorgi
3
Como @Yorgi - dentro do adaptador parece útil. Gostaria de saber se existe algum padrão que você possa desenvolver usando o onBindViewHolder para rastrear quais estão realmente na tela enquanto um usuário rola.
você precisa saber é o seguinte
7
getItemCountpode retornar 1 e findFirstVisibleItemPosition-1 na mesma chamada.
mBMC
4
o que você pode sugerir sobre o StaggeredLayoutManager?
hornet2319
37
Esses métodos são tão pouco confiáveis ​​que são completamente inúteis. Especialmente depois de notifyDataSetChanged / itemRemoved / RangeChanged
JK
12

Por fim, encontrei uma solução para saber se o item atual está visível, no evento onBindViewHolder no adaptador.

A chave é o método isViewPartiallyVisible do LayoutManager.

No seu adaptador, você pode obter o LayoutManager no RecyclerView, que você obtém como parâmetro no evento onAttachedToRecyclerView .

Ernesto Vega
fonte
Mas onde você chamaria esse método no qual o gerenciador de layout não é nulo?
6rchid
Você precisa aguardar o evento onAttachedToRecyclerView do adaptador. Nesse caso, você recebe o RecyclerView como parâmetro; e você pode obter o LayoutManager no RecyclerVie e salvá-lo em uma var global. Se o LayoutManager for nulo, provavelmente pode ser porque não foi atribuído ao RecyclerView em Activity / Fragment / Layout; e tente construir o adaptador após essa atribuição.
Ernesto Vega
De acordo com o código-fonte, isViewPartiallyVisible está muito danificado. Se completamente Visível for verdadeiro, ele retornará verdadeiro se a visualização estiver totalmente visível. No entanto, se falso, apenas nega o resultado que retornará verdadeiro se a exibição for parcialmente visível ou não visível. Até a documentação não faz sentido.
Molanda 12/11/19
9

para aqueles que têm uma lógica a ser implementada dentro do adaptador RecyclerView, você ainda pode usar a abordagem @ernesto combinada com um on scrollListener para obter what you wantcomo o RecyclerView é consultado. Dentro do adaptador, você terá algo parecido com isto:

@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"));
                        }
                }
            });
        }
    }
Aleyam
fonte
7

Você pode usar recyclerView.getChildAt()para obter cada filho visível, e definir alguma tag convertview.setTag(index)nessas visualizações no código do adaptador ajudará você a relacioná-lo com os dados do adaptador.

Sreejith B Naick
fonte
O problema com getChildAt () é que a ordem dos elementos pode estar fora de 5 elementos: 0, 5, 4, 3, 2, 1 (a contagem de filhos é maioritariamente> = a contagem de itens visíveis). Então, tentei obter a ordem do elemento via getGlobalVisibleRect.
rekire
Qual é o seu requisito real: obter filho visível (filho dentro da tela) na ordem real?
Sreejith B Naick
Agora eu quero saber qual elemento está no centro, mais tarde talvez eu também esteja interessado nos limites.
rekire
1
Você só receberá itens visíveis recyclerView.getChildAt(), é assim que geralmente RecyclerViewfunciona. RecyclerViewtentará manter apenas algumas visualizações secundárias que estão visíveis no momento (ou seja, dentro dos limites da tela, não Visibilidade como INTEIRA, INVISÍVEL) e tentará reciclar essas visualizações quando o usuário rolar.
Sreejith B Naick
6
Exibir visibleChild = recyclerView.getChildAt (0); int positionOfChild = recyclerView.getChildAdapterPosition (visibleChild);
Kevin Lee
5

Adendo :

As funções propostas FindLast ... Posição () que não funcionam corretamente em um cenário com uma barra de ferramentas em colapso, enquanto a barra de ferramentas é expandida.

Parece que a visão do reciclador tem uma altura fixa e, enquanto a barra de ferramentas é expandida, o reciclador é movido para baixo, parcialmente fora da tela. Como conseqüência, os resultados das funções propostas são muito altos. Exemplo: Diz-se que o último item visível é o nº 9, mas, na verdade, o item 7 é o último que está na tela.

Esse comportamento também é a razão pela qual minha visão frequentemente falhava ao rolar para a posição correta, ou seja, scrollToPosition () não funcionava corretamente (finalmente fechei a barra de ferramentas programaticamente).

Andreas K. aus M.
fonte
Isso é verdade, mas é assim que a barra de ferramentas recolhida funciona. Parei de desenvolver aplicativos Android há um ano, mas me lembro desse fato.
Rekire 21/05/19
4

Os Linear / Grid LayoutManagermétodos a seguir podem ser usados ​​para verificar quais itens estãovisible

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

e se você deseja rastrear is item visible on screenalgum limite, consulte o blog a seguir.

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

Sumit Jain
fonte
3

Para StaggeredGridLayoutManagerfazer isso:

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

E para obter visualizações de itens visíveis:

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

Lembre-se de verificar se está vazio.

Douglas Nassif Roma Junior
fonte
O que você quer dizer com "verificar se está vazio"? Como se verifica?
tmm1
viewsIdsé uma matriz e pode estar vazia.
Douglas Nassif Roma Junior