Nhận các mục hiển thị trong RecyclerView


268

Tôi cần biết những yếu tố nào hiện đang được hiển thị trong RecyclerView của tôi. Không có tương đương với OnScrollListener.onScroll(...)phương thức trên ListViews. Tôi đã cố gắng làm việc với View.getGlobalVisibleRect(...), nhưng bản hack đó quá xấu và không phải lúc nào cũng hoạt động.

Ai đó có ý kiến ​​gì không?

Câu trả lời:


579

Con đầu tiên / cuối nhìn thấy phụ thuộc vào LayoutManager. Nếu bạn đang sử dụng LinearLayoutManagerhoặc GridLayoutManager, bạn có thể sử dụng

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

Ví dụ:

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

Đối với LinearLayoutManager, đầu tiên / cuối cùng phụ thuộc vào thứ tự bộ chuyển đổi. Đừng truy vấn trẻ em từ RecyclerView; LayoutManagercó thể thích bố trí nhiều mục hơn hiển thị cho bộ nhớ đệm.


10
Có bất kỳ khả năng nào để truy cập các phương thức này từ RecyclerView.Ad CHƯƠNG mà không chuyển tham chiếu đến LayoutManager không?
Yorgi

3
Giống như @Yorgi - bên trong bộ chuyển đổi có vẻ hữu ích. Tôi tự hỏi nếu có một số mẫu bạn có thể phát triển khi sử dụng onBindViewHolder để theo dõi những mẫu nào thực sự trên màn hình trong khi người dùng cuộn.
RoundSparrow hilltx

7
getItemCountcó thể trả về 1 và findFirstVisibleItemPosition-1 trên cùng một cuộc gọi.
mbmc

4
Bạn có thể đề xuất gì về StaggeredLayoutManager?
hornet2319

37
Những phương pháp này không đáng tin cậy đến mức chúng hoàn toàn vô dụng. Đặc biệt là sau khi thông báoDataSetChanged / itemRemond / RangeChanged
JK

12

Cuối cùng, tôi tìm thấy một giải pháp để biết liệu mục hiện tại có hiển thị hay không, từ sự kiện onBindViewHolder trong bộ điều hợp.

Điều quan trọng là phương thức isViewPartivelyVisible từ LayoutManager.

Trong bộ điều hợp của bạn, bạn có thể lấy Trình quản lý bố cục từ RecyclerView, mà bạn nhận được dưới dạng tham số từ sự kiện onAttachedToRecyclerView .


Nhưng bạn sẽ gọi phương thức này ở đâu trong đó trình quản lý bố cục không phải là null?
6

Bạn cần chờ sự kiện onAttachedToRecyclerView của bộ chuyển đổi. Trong trường hợp đó, bạn nhận được RecyclerView làm tham số; và sau đó bạn có thể lấy LayoutManager từ RecyclerVie và lưu nó trong một var toàn cục. Nếu LayoutManager là null, có thể là do nó không được gán cho RecyclerView trong Activity / Fragment / Layout; và cố gắng xây dựng bộ chuyển đổi sau khi chuyển nhượng đó.
Ernesto Vega

Theo mã nguồn, isViewPartivelyVisible bị hỏng nặng. Nếu hoàn toàn vô hình là đúng, nó sẽ trả về đúng nếu chế độ xem hoàn toàn hiển thị. Tuy nhiên, nếu sai, nó chỉ phủ nhận kết quả trả về true nếu chế độ xem được hiển thị một phần hoặc không hiển thị. Ngay cả các tài liệu không có ý nghĩa.
Molanda


9

đối với những người có logic được triển khai bên trong bộ điều hợp RecyclerView, bạn vẫn có thể sử dụng phương pháp @ernesto kết hợp với scrollListener để lấy what you wantkhi RecyclerView được tư vấn. Bên trong bộ chuyển đổi, bạn sẽ có một cái gì đó như thế này:

@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

Bạn có thể sử dụng recyclerView.getChildAt()để nhận từng đứa trẻ hiển thị và đặt một số thẻ convertview.setTag(index)trên các chế độ xem này trong mã bộ điều hợp sẽ giúp bạn liên kết nó với dữ liệu bộ điều hợp.


Vấn đề với getChildAt () là thứ tự của các phần tử có thể nằm ngoài 5 phần tử: 0, 5, 4, 3, 2, 1 (số lượng con chủ yếu là> = số lượng các mục hiển thị). Vì vậy, tôi đã cố gắng để có được thứ tự của phần tử thông qua getGlobalVisibleRect.
thiệu

Yêu cầu thực tế của bạn là gì, có thể nhìn thấy đứa trẻ (đứa trẻ bên trong màn hình bị ràng buộc) theo thứ tự thực tế?
Sreejith B Naick

Bây giờ tôi muốn biết phần tử nào ở trung tâm, sau này tôi cũng có thể quan tâm đến giới hạn.
thiệu

1
Bạn sẽ chỉ nhận được các mục có thể nhìn thấy từ đó recyclerView.getChildAt(), đó là cách thức RecyclerViewhoạt động nói chung . RecyclerViewsẽ cố gắng chỉ giữ một vài chế độ xem trẻ em hiện có thể nhìn thấy (ví dụ: trong giới hạn màn hình, không hiển thị dưới dạng Gone, BÍ MẬT) và cố gắng tái chế các chế độ xem này khi người dùng cuộn.
Sreejith B Naick

6
Xem thấyChild = recyclerView.getChildAt (0); int locationOfChild = recyclerView.getChildAd ModuleP vị trí (viewerChild);
Kevin Lee

5

Phụ lục :

Các chức năng đề xuất findLast ... Vị trí () làm không hoạt động chính xác trong một kịch bản với một thanh công cụ bị sụp đổ trong khi thanh công cụ được mở rộng.

Có vẻ như chế độ xem của trình tái chế có chiều cao cố định và trong khi thanh công cụ được mở rộng, trình tái chế được di chuyển xuống, một phần ra khỏi màn hình. Kết quả là kết quả của các chức năng được đề xuất là quá cao. Ví dụ: Mục hiển thị cuối cùng được cho là số 9, nhưng trên thực tế, mục số 7 là mục cuối cùng trên màn hình.

Hành vi này cũng là lý do tại sao chế độ xem của tôi thường không cuộn đến đúng vị trí, tức là scrollToP vị trí () không hoạt động chính xác (cuối cùng tôi đã thu gọn thanh công cụ theo chương trình).


Đó là sự thật, nhưng đây là cách thanh công cụ sụp đổ hoạt động. Tôi đã ngừng phát triển Ứng dụng Android một năm trước, nhưng tôi có thể nhớ điều đó.
thiệu

4

Các Linear / Grid LayoutManagerphương pháp sau đây có thể được sử dụng để kiểm tra những mục nàovisible

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

và nếu bạn muốn theo dõi is item visible on screenmột số ngưỡng thì bạn có thể tham khảo blog sau.

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


3

Để StaggeredGridLayoutManagerlàm điều này:

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

Và để có được lượt xem mục hiển thị:

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

Nhớ kiểm tra xem nó có trống không.


Bạn có ý nghĩa gì "kiểm tra nếu nó trống"? Làm thế nào để kiểm tra?
tmm1

viewsIdslà một mảng, và nó có thể trống.
Douglas Nassif Roma Junior
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.