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.


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 .


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

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.


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).


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


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.


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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.