在RecyclerView中获取可见项目

rek*_*ire 249 android android-recyclerview

我需要知道我的RecyclerView当前显示哪些元素.OnScrollListener.onScroll(...)ListViews 上的方法没有等价物.我尝试过View.getGlobalVisibleRect(...),但是那个黑客太丑了,并不总是有用.

有人有什么想法吗?

yig*_*git 547

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

int findFirstVisibleItemPosition();
int findFirstCompletelyVisibleItemPosition();
int findLastVisibleItemPosition();
int findLastCompletelyVisibleItemPosition();
Run Code Online (Sandbox Code Playgroud)

例如:

GridLayoutManager layoutManager = ((GridLayoutManager)mRecyclerView.getLayoutManager());
int firstVisiblePosition = layoutManager.findFirstVisibleItemPosition();
Run Code Online (Sandbox Code Playgroud)

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

  • 这些方法非常不可靠,完全没用.特别是在notifyDataSetChanged/itemRemoved/RangeChanged之后 (33认同)
  • 是否有可能从RecyclerView.Adapter访问此方法而不传递对LayoutManager的引用? (8认同)
  • `getItemCount`可以在同一个调用中返回1和`findFirstVisibleItemPosition` -1. (6认同)
  • 你有什么建议StaggeredLayoutManager? (4认同)
  • 像@Yorgi一样 - 适配器内部似乎很有用.我想知道是否有一些模式你可以使用onBindViewHolder在用户滚动时跟踪哪些实际在屏幕上. (3认同)
  • findFirstCompletelyVisibleItemPosition(); 适用于在显示器上完全显示的项目..那个屏幕更长的项目怎么样? (2认同)
  • 我来到这里找到可靠使用的方法,以获得AFTER notify*Changed/Removed等方法调用的位置.仍然没有找到答案.:/ (2认同)
  • findLastVisibleItemPosition 返回列表的最后一项,而不是最后一项,即视图。例如,recyclerview 有 23 个条目,只有 5 个可见。所以 findLastVisibleItemPosition 返回它返回 23 而不是 5 (2认同)

Ale*_*yam 19

对于那些在 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"));
                        }
                }
            });
        }
    }
Run Code Online (Sandbox Code Playgroud)


Ish*_*eur 12

上面的每个答案都是正确的,我还想添加我的工作代码的快照。

recycler.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);
           // Some code when initially scrollState changes
        }

        @Override
        public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
            // Some code while the list is scrolling
            LinearLayoutManager lManager = (LinearLayoutManager) recyclerView.getLayoutManager();
            int firstElementPosition = lManager.findFirstVisibleItemPosition();
            
        }
    });
Run Code Online (Sandbox Code Playgroud)


Ern*_*ega 11

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

关键是LayoutManager中的方法isViewPartiallyVisible.

在适配器中,您可以从RecyclerView获取LayoutManager,您可以从onAttachedToRecyclerView事件获取该参数.


小智 8

附录

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

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

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


Sre*_*ick 7

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

  • 查看visibleChild = recyclerView.getChildAt(0); int positionOfChild = recyclerView.getChildAdapterPosition(visibleChild); (4认同)

Sum*_*ain 7

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

int findFirstVisibleItemPosition();
int findLastVisibleItemPosition();
int findFirstCompletelyVisibleItemPosition();
int findLastCompletelyVisibleItemPosition();
Run Code Online (Sandbox Code Playgroud)

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

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


Dou*_*ior 5

为此StaggeredGridLayoutManager

RecyclerView rv = findViewById(...);
StaggeredGridLayoutManager lm = new StaggeredGridLayoutManager(...);
rv.setLayoutManager(lm);
Run Code Online (Sandbox Code Playgroud)

并获取可见项目视图:

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

记得检查一下是否为空。