Dapatkan item yang terlihat di RecyclerView

Jawaban:

579

Anak terlihat pertama / terakhir tergantung pada LayoutManager. Jika Anda menggunakan LinearLayoutManageratau GridLayoutManager, Anda dapat menggunakan

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

Sebagai contoh:

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

Sebab LinearLayoutManager, pertama / terakhir tergantung pada pemesanan adaptor. Jangan meminta anak-anak dari RecyclerView; LayoutManagermungkin lebih suka mengatur lebih banyak item daripada yang terlihat untuk caching.

yigit
sumber
10
Apakah ada kemungkinan untuk mengakses metode ini dari RecyclerView.Adapter tanpa melewati referensi ke LayoutManager?
Yorgi
3
Seperti @Yorgi - di dalam adaptor sepertinya berguna. Saya ingin tahu apakah ada beberapa pola yang dapat Anda kembangkan dalam menggunakan onBindViewHolder untuk melacak mana yang sebenarnya ada di layar saat pengguna menggulir.
RoundSparrow hilltx
7
getItemCountdapat mengembalikan 1 dan findFirstVisibleItemPosition-1 pada panggilan yang sama.
mbmc
4
apa yang bisa Anda sarankan tentang StaggeredLayoutManager?
hornet2319
37
Metode-metode ini sangat tidak dapat diandalkan sehingga sama sekali tidak berguna. Terutama setelah notifyDataSetChanged / itemRemoved / RangeChanged
JK
12

Akhirnya, saya menemukan solusi untuk mengetahui apakah item saat ini terlihat, dari peristiwa onBindViewHolder di adaptor.

Kuncinya adalah metode isViewPartiallyVisible dari LayoutManager.

Di adaptor Anda, Anda bisa mendapatkan LayoutManager dari RecyclerView, yang Anda dapatkan sebagai parameter dari acara onAttachedToRecyclerView .

Ernesto Vega
sumber
Tetapi di mana Anda akan memanggil metode ini di mana manajer tata letak tidak nol?
6rchid
Anda harus menunggu acara onAttachedToRecyclerView dari adaptor. Dalam peristiwa itu Anda menerima RecyclerView sebagai parameter; dan kemudian Anda bisa mendapatkan LayoutManager dari RecyclerVie, dan menyimpannya dalam global var. Jika LayoutManager adalah nol, mungkin bisa karena itu tidak ditugaskan ke RecyclerView di Activity / Fragment / Layout; dan mencoba membangun adaptor setelah penugasan itu.
Ernesto Vega
Menurut kode sumber, isViewPartiallyVisible rusak parah. Jika sepenuhnyaVisible benar, itu akan mengembalikan benar jika tampilan sepenuhnya terlihat. Namun, jika salah, itu hanya meniadakan hasil yang mengembalikan true jika tampilan sebagian terlihat atau tidak terlihat. Bahkan dokumentasinya tidak masuk akal.
Molanda
9

bagi mereka yang memiliki logika untuk diimplementasikan di dalam adaptor RecyclerView Anda masih dapat menggunakan pendekatan @ernesto dikombinasikan dengan pada scrollListener untuk mendapatkan what you wantsebagai berkonsultasi dengan RecyclerView. Di dalam adaptor Anda akan memiliki sesuatu seperti ini:

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

Anda dapat menggunakan recyclerView.getChildAt()untuk mendapatkan setiap anak yang terlihat, dan menetapkan beberapa tag convertview.setTag(index)pada tampilan ini dalam kode adaptor akan membantu Anda untuk menghubungkannya dengan data adaptor.

Sreejith B Naick
sumber
Masalah dengan getChildAt () adalah bahwa urutan elemen dapat dari 5 elemen: 0, 5, 4, 3, 2, 1 (jumlah anak sebagian besar> = jumlah item yang terlihat). Jadi saya mencoba untuk mendapatkan urutan elemen melalui getGlobalVisibleRect.
bangkit
Apa kebutuhan Anda yang sebenarnya, dapatkan anak yang terlihat (anak di dalam layar terikat) dalam urutan yang sebenarnya?
Sreejith B Naick
Sekarang saya ingin tahu elemen mana yang ada di tengah, nanti saya mungkin juga tertarik dengan batasannya.
bangkit
1
Anda hanya akan mendapatkan item yang terlihat dari recyclerView.getChildAt(), itulah cara umumnya RecyclerViewbekerja. RecyclerViewakan mencoba untuk menahan hanya beberapa tampilan anak yang saat ini terlihat (yaitu; dalam batas layar, bukan Visibilitas sebagai GONE, TIDAK TERLIHAT) dan mencoba untuk mendaur ulang tampilan ini ketika pengguna menggulir.
Sreejith B Naick
6
Lihat visibleChild = recyclerView.getChildAt (0); int positionOfChild = recyclerView.getChildAdapterPosition (visibleChild);
Kevin Lee
5

Addendum :

fungsi yang diusulkan findLast ... Posisi () tidak tidak bekerja dengan benar dalam skenario dengan toolbar runtuh sementara toolbar diperluas.

Tampaknya tampilan pendaur ulang memiliki ketinggian tetap, dan sementara bilah alat diperluas, pendaur ulang dipindahkan ke bawah, sebagian keluar dari layar. Akibatnya, hasil fungsi yang diusulkan terlalu tinggi. Contoh: Item yang terlihat terakhir dikatakan sebagai # 9, tetapi sebenarnya item # 7 adalah yang terakhir yang ada di layar.

Perilaku ini juga merupakan alasan mengapa tampilan saya sering gagal untuk menggulir ke posisi yang benar, yaitu scrollToPosition () tidak berfungsi dengan benar (saya akhirnya menciutkan bilah alat pemrograman).

Andreas K. aus M.
sumber
Itu benar, tetapi ini adalah cara kerja bilah alat runtuh. Saya berhenti mengembangkan Aplikasi Android setahun yang lalu, tetapi saya dapat mengingat fakta itu.
hidup kembali
4

Berikut Linear / Grid LayoutManagermetode dapat digunakan untuk memeriksa itemvisible

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

dan jika Anda ingin melacak is item visible on screenambang tertentu maka Anda dapat merujuk ke blog berikut.

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

Sumit Jain
sumber
3

Untuk StaggeredGridLayoutManagermelakukan ini:

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

Dan untuk mendapatkan tampilan item yang terlihat:

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

Ingatlah untuk memeriksa apakah itu kosong.

Douglas Nassif Roma Junior
sumber
Apa maksudmu "periksa apakah kosong"? Bagaimana cara mengeceknya?
tmm1
viewsIdsadalah array, dan mungkin kosong.
Douglas Nassif Roma Junior