Android 在 RecyclerView 中获取可见项目

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24989218/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 08:59:18  来源:igfitidea点击:

Get visible items in RecyclerView

androidandroid-recyclerview

提问by rekire

I need to know which elements are currently displayed in my RecyclerView. There is no equivalent to the OnScrollListener.onScroll(...)method on ListViews. I tried to work with View.getGlobalVisibleRect(...), but that hack is too ugly and does not always work too.

我需要知道当前在我的 RecyclerView 中显示了哪些元素。没有与OnScrollListener.onScroll(...)ListViews上的方法等效的方法。我试图与 一起工作View.getGlobalVisibleRect(...),但这种 hack 太丑陋了,而且并不总是有效。

Someone any ideas?

有人有什么想法吗?

回答by yigit

First / last visible child depends on the LayoutManager. If you are using LinearLayoutManageror GridLayoutManager, you can use

第一个/最后一个可见的孩子取决于LayoutManager. 如果您正在使用LinearLayoutManagerGridLayoutManager,则可以使用

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

For example:

例如:

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

For LinearLayoutManager, first/last depends on the adapter ordering. Don't query children from RecyclerView; LayoutManagermay prefer to layout more items than visible for caching.

对于LinearLayoutManager,第一个/最后一个取决于适配器排序。不要从RecyclerView;询问孩子;LayoutManager可能更喜欢布局比缓存可见的更多项目。

回答by Ernesto Vega

Finally, I found a solution to know if the current item is visible, from the onBindViewHolder event in the adapter.

最后,我找到了一个解决方案,通过适配器中的 onBindViewHolder 事件了解当前项是否可见。

The key is the method isViewPartiallyVisiblefrom LayoutManager.

关键是LayoutManager 中的isViewPartiallyVisible方法。

In your adapter, you can get the LayoutManager from the RecyclerView, which you get as parameter from the onAttachedToRecyclerViewevent.

在您的适配器中,您可以从 RecyclerView 获取 LayoutManager,您可以从onAttachedToRecyclerView事件中获取它作为参数。

回答by Aleyam

for those who have a logic to be implemented inside the RecyclerView adapter you can still use @ernesto approach combined with an on scrollListener to get what you wantas the RecyclerView is consulted. Inside the adapter you will have something like this:

对于那些在 RecyclerView 适配器中实现逻辑的人,您仍然可以使用 @ernesto 方法结合 on scrollListener 来获取what you wantRecyclerView 的咨询。在适配器内部,您将拥有如下内容:

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

回答by Sreejith B Naick

You can use recyclerView.getChildAt()to get each visible child, and setting some tag convertview.setTag(index)on these view in adapter code will help you to relate it with adapter data.

您可以使用recyclerView.getChildAt()获取每个可见的孩子,并convertview.setTag(index)在适配器代码中在这些视图上设置一些标签将帮助您将其与适配器数据相关联。

回答by Sumit Jain

Following Linear / Grid LayoutManagermethods can be used to check which items are visible

Linear / Grid LayoutManager可以使用以下方法检查哪些项目是visible

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

and if you want to track is item visible on screenfor some threshold then you can refer to the following blog.

如果您想跟踪is item visible on screen某个阈值,则可以参考以下博客。

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

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

回答by Andreas K. aus M.

Addendum:

The proposed functions findLast...Position()do notwork correctly in a scenario with a collapsing toolbar while the toolbar is expanded.

It seems that the recycler view has a fixed height, and while the toolbar is expanded, the recycler is moved down, partially out of the screen. As a consequence the results of the proposed functions are too high. Example: The last visible item is told to be #9, but in fact item #7 is the last one that is on screen.

This behaviour is also the reason why my view often failed to scroll to the correct position, i.e. scrollToPosition() did not work correctly (I finally collapsed the toolbar programmatically).

附录

建议的功能FindLast中...位置()正确的情况下用折叠式工具,而工具栏上展开工作。

似乎回收器视图具有固定的高度,当工具栏展开时,回收器向下移动,部分移出屏幕。因此,建议函数的结果太高。示例:最后一个可见项目被告知是#9,但实际上项目#7 是屏幕上的最后一个。

这种行为也是我的视图经常无法滚动到正确位置的原因,即 scrollToPosition() 无法正常工作(我最终以编程方式折叠了工具栏)。

回答by Douglas Nassif Roma Junior

For StaggeredGridLayoutManagerdo this:

为此StaggeredGridLayoutManager

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

And to get visible item views:

并获得可见的项目视图:

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

Remember to check if it is empty.

记得检查它是否为空。