Obtener elementos visibles en RecyclerView

Respuestas:

579

El primer / último hijo visible depende de LayoutManager. Si está usando LinearLayoutManagero GridLayoutManager, puede usar

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

Por ejemplo:

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

Para LinearLayoutManager, primero / último depende del orden del adaptador. No pregunte a los niños de RecyclerView; LayoutManagerEs posible que prefiera diseñar más elementos que los visibles para el almacenamiento en caché.

yigit
fuente
10
¿Existe alguna posibilidad de acceder a estos métodos desde RecyclerView.Adapter sin pasar referencia a LayoutManager?
Yorgi
3
Como @Yorgi, dentro del adaptador parece útil. Me pregunto si hay algún patrón que pueda desarrollar al usar onBindViewHolder para rastrear cuáles están realmente en la pantalla mientras un usuario se desplaza.
RoundSparrow hilltx
77
getItemCountpuede devolver 1 y findFirstVisibleItemPosition-1 en la misma llamada.
mbmc
44
¿Qué puede sugerir sobre StaggeredLayoutManager?
hornet2319
37
Estos métodos son tan poco confiables que son completamente inútiles. Especialmente después de notifyDataSetChanged / itemRemoved / RangeChanged
JK
12

Finalmente, encontré una solución para saber si el elemento actual es visible, desde el evento onBindViewHolder en el adaptador.

La clave es el método isViewPartiallyVisible de LayoutManager.

En su adaptador, puede obtener el LayoutManager de RecyclerView, que obtiene como parámetro del evento onAttachedToRecyclerView .

Ernesto Vega
fuente
Pero, ¿dónde llamarías a este método en el que el administrador de diseño no es nulo?
6rchid
Debe esperar el evento onAttachedToRecyclerView del adaptador. En ese caso, recibe el RecyclerView como parámetro; y luego puede obtener el LayoutManager de RecyclerVie y guardarlo en una variable global. Si el LayoutManager es nulo, probablemente podría deberse a que no se asignó a RecyclerView en Activity / Fragment / Layout; e intente construir el adaptador después de esa asignación.
Ernesto Vega
Según el código fuente, isViewPartiallyVisible está muy dañado. Si completamente Visible es verdadero, volverá verdadero si la vista es completamente visible. Sin embargo, si es falso, solo niega el resultado que devuelve verdadero si la vista es parcialmente visible o no visible. Incluso la documentación no tiene sentido.
Molanda
9

para aquellos que tienen que implementar una lógica dentro del adaptador RecyclerView, aún pueden usar el enfoque @ernesto combinado con un en scrollListener para obtener información sobre what you wantcómo consultar el RecyclerView. Dentro del adaptador tendrás algo como esto:

@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
fuente
7

Puede usar recyclerView.getChildAt()para obtener cada elemento secundario visible, y establecer alguna etiqueta convertview.setTag(index)en estas vistas en el código del adaptador lo ayudará a relacionarlo con los datos del adaptador.

Sreejith B Naick
fuente
El problema con getChildAt () es que el orden de los elementos puede estar fuera de 5 elementos: 0, 5, 4, 3, 2, 1 (el recuento secundario es mayormente> = el recuento de elementos visibles). Así que intenté obtener el orden del elemento a través de getGlobalVisibleRect.
rekire
¿Cuál es su requisito real, obtener niño visible (niño dentro de la pantalla encuadernada) en orden real?
Sreejith B Naick
Ahora quiero saber qué elemento está en el centro, más tarde quizás también me interesen los límites.
rekire
1
Solo obtendrá elementos visibles de recyclerView.getChildAt(), así es como generalmente RecyclerViewfunciona. RecyclerViewintentará mantener solo unas pocas vistas secundarias que están actualmente visibles (es decir, dentro de los límites de la pantalla, no Visibilidad como IDA, INVISIBLE) e intentará reciclar estas vistas cuando el usuario se desplace.
Sreejith B Naick
66
Ver visibleChild = recyclerView.getChildAt (0); int positionOfChild = recyclerView.getChildAdapterPosition (visibleChild);
Kevin Lee
5

Adición :

Las funciones propuestas FindLast ... de posición () no no funcionan correctamente en un escenario con una barra de herramientas, mientras que el colapso de la barra de herramientas se expande.

Parece que la vista del reciclador tiene una altura fija, y mientras la barra de herramientas se expande, el reciclador se mueve hacia abajo, parcialmente fuera de la pantalla. Como consecuencia, los resultados de las funciones propuestas son demasiado altos. Ejemplo: se dice que el último elemento visible es el # 9, pero de hecho, el elemento # 7 es el último que está en la pantalla.

Este comportamiento también es la razón por la cual mi vista a menudo no pudo desplazarse a la posición correcta, es decir, scrollToPosition () no funcionó correctamente (finalmente colapsé la barra de herramientas mediante programación).

Andreas K. aus M.
fuente
Eso es cierto, pero así es como funciona la barra de herramientas contraída. Dejé de desarrollar aplicaciones de Android hace un año, pero puedo recordar ese hecho.
rekire
4

Los siguientes Linear / Grid LayoutManagermétodos se pueden utilizar para verificar qué elementos sonvisible

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

y si desea realizar un seguimiento is item visible on screende algún umbral, puede consultar el siguiente blog.

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

Sumit Jain
fuente
3

Para StaggeredGridLayoutManagerhacer esto:

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

Y para obtener vistas visibles del elemento:

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

Recuerde verificar si está vacío.

Douglas Nassif Roma Junior
fuente
¿Qué quiere decir "comprobar si está vacío"? ¿Cómo se comprueba uno?
tmm1
viewsIdses una matriz y puede estar vacía.
Douglas Nassif Roma Junior