Uzyskaj widoczne elementy w RecyclerView


Odpowiedzi:


578

Pierwsze / ostatnie widoczne dziecko zależy od LayoutManager. Jeśli używasz LinearLayoutManagerlub GridLayoutManager, możesz użyć

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

Na przykład:

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

Dla LinearLayoutManagerpierwszego / ostatniego zależy od zamówienia adaptera. Nie pytaj dzieci od RecyclerView; LayoutManagermoże preferować układanie większej liczby elementów niż jest widoczne do buforowania.


10
Czy jest jakaś możliwość dostępu do tych metod z RecyclerView.Adapter bez przekazywania odniesienia do LayoutManager?
Yorgi,

3
Jak @Yorgi - wewnątrz adaptera wydaje się przydatny. Zastanawiam się, czy istnieje jakiś wzorzec, który można rozwinąć za pomocą onBindViewHolder do śledzenia, które z nich są na ekranie podczas przewijania użytkownika.
RoundSparrow hilltx

7
getItemCountmoże zwrócić 1 i findFirstVisibleItemPosition-1 dla tego samego połączenia.
mbmc

4
co możesz zasugerować na temat StaggeredLayoutManager?
hornet2319,

37
Metody te są tak zawodne, że są całkowicie bezużyteczne. Zwłaszcza po powiadomieniuDataSetChanged / itemRemoved / RangeChanged
JK

12

Wreszcie znalazłem rozwiązanie pozwalające stwierdzić, czy bieżący element jest widoczny, na podstawie zdarzenia onBindViewHolder w adapterze.

Kluczem jest metoda isViewPartIALVisible z LayoutManager.

W adapterze możesz pobrać LayoutManager z RecyclerView, który otrzymasz jako parametr ze zdarzenia onAttachedToRecyclerView .


Ale gdzie nazwałbyś tę metodę, w której menedżer układu nie jest pusty?
6rchid

Musisz poczekać na zdarzenie onAttachedToRecyclerView adaptera. W takim przypadku otrzymasz RecyclerView jako parametr; a następnie możesz pobrać LayoutManager z RecyclerVie i zapisać go w zmiennej globalnej. Jeśli LayoutManager ma wartość NULL, prawdopodobnie może to wynikać z tego, że nie został przypisany do RecyclerView w Activity / Fragment / Layout; i spróbuj zbudować adapter po tym przypisaniu.
Ernesto Vega

Według kodu źródłowego isViewPartIALVisible jest poważnie uszkodzony. Jeśli parametr trueVisible jest prawdziwy, zwróci wartość true, jeśli widok jest w pełni widoczny. Jednak jeśli jest fałszywy, to po prostu neguje wynik, który zwraca true, jeśli widok jest częściowo widoczny lub niewidoczny. Nawet dokumentacja nie ma sensu.
Molanda,


9

dla tych, którzy mają logikę, która ma zostać zaimplementowana w adapterze RecyclerView, możesz nadal korzystać z podejścia @ernesto w połączeniu z funkcją scrollListener, aby uzyskać dostęp what you wantdo RecyclerView. Wewnątrz adaptera znajdziesz coś takiego:

@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

Możesz użyć, recyclerView.getChildAt()aby uzyskać każde widoczne dziecko, a ustawienie tagu convertview.setTag(index)w tym widoku w kodzie adaptera pomoże ci powiązać go z danymi adaptera.


Problem z getChildAt () polega na tym, że kolejność elementów może wynosić 5 elementów: 0, 5, 4, 3, 2, 1 (liczba potomków to w większości> = liczba widocznych elementów). Próbowałem więc uzyskać kolejność elementu za pośrednictwem getGlobalVisibleRect.
rekire

Jakie jest Twoje rzeczywiste wymaganie, aby widoczne dziecko (dziecko wewnątrz ekranu było powiązane) w rzeczywistej kolejności?
Sreejith B Naick

Teraz chcę wiedzieć, który element znajduje się w środku, później może też interesują mnie granice.
rekire

1
Dostaniesz tylko widoczne przedmioty recyclerView.getChildAt(), tak na ogół RecyclerViewdziała. RecyclerViewspróbuje zatrzymać tylko kilka widoków potomnych, które są obecnie widoczne (tj. w granicach ekranu, a nie Widoczność jako BRAK, NIEWIDOCZNE) i spróbuje przetworzyć te widoki, gdy użytkownik przewinie.
Sreejith B Naick

6
Wyświetl visibleChild = recyclinglerView.getChildAt (0); int positionOfChild = recyclerView.getChildAdapterPosition (visibleChild);
Kevin Lee

4

Linear / Grid LayoutManagerAby sprawdzić, które elementy są, można zastosować następujące metodyvisible

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

a jeśli chcesz śledzić is item visible on screendla pewnego progu, możesz odnieść się do następującego bloga.

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


4

Uzupełnienie :

Proponowane funkcje findLast ... position () ma nie działać prawidłowo w scenariuszu z paska narzędzi zapadającego natomiast pasek narzędzi jest rozszerzony.

Wygląda na to, że widok recyklera ma stałą wysokość i podczas gdy pasek narzędzi jest rozwinięty, recykler jest przesuwany w dół, częściowo poza ekran. W konsekwencji wyniki proponowanych funkcji są zbyt wysokie. Przykład: Mówi się, że ostatnim widocznym przedmiotem jest numer 9, ale w rzeczywistości element 7 jest ostatnim, który jest na ekranie.

To zachowanie jest również przyczyną, dla której mój widok często nie przewijał się do prawidłowej pozycji, tj. ScrollToPosition () nie działał poprawnie (w końcu programowo zwinąłem pasek narzędzi).


To prawda, ale tak działa składany pasek narzędzi. Rok temu przestałem tworzyć aplikacje na Androida, ale pamiętam ten fakt.
rekire

3

Aby StaggeredGridLayoutManagerto zrobić:

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

Aby uzyskać widoczne widoki elementów:

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

Pamiętaj, aby sprawdzić, czy jest pusty.


Co masz na myśli „sprawdź, czy jest pusty”? Jak się sprawdza?
tmm1

viewsIdsjest tablicą i może być pusta.
Douglas Nassif Roma Junior
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.