在RecyclerView中获取可见的物品


Answers:


578

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

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

例如:

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

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


10
是否有可能在不将引用传递给LayoutManager的情况下从RecyclerView.Adapter访问此方法?
Yorgi 2014年

3
就像@Yorgi一样-适配器内部似乎很有用。我想知道是否可以使用onBindViewHolder开发某种模式来跟踪用户滚动时实际上在屏幕上显示的模式。
RoundSparrow hilltx 2015年

7
getItemCount可以findFirstVisibleItemPosition在同一通话中返回1和-1。
mbmc

4
您对StaggeredLayoutManager有什么建议?
hornet2319 2015年

37
这些方法非常不可靠,完全没有用。特别是在notifyDataSetChanged / itemRemoved / RangeChanged
JK

12

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

关键是LayoutManager中的isViewPartiallyVisible方法。

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


但是,在布局管理器不为null的情况下,您将在哪里调用此方法呢?
rchid

您需要等待适配器的onAttachedToRecyclerView事件。在这种情况下,您将收到RecyclerView作为参数;然后您可以从RecyclerVie获取LayoutManager,并将其保存在全局变量中。如果LayoutManager为null,则可能是因为它没有在Activity / Fragment / Layout中分配给RecyclerView;并尝试在分配后构建适配器。
Ernesto Vega

根据源代码,isViewPartiallyVisible严重损坏。如果fullyVisible为true,则在视图完全可见时将返回true。但是,如果为false,则只对结果取反,如果视图部分可见或不可见,则返回true。甚至文档也没有意义。
Molanda


9

对于那些在RecyclerView适配器内部实现逻辑的用户,您仍然可以使用@ernesto方法与on scrollListener结合使用,以获取what you want有关RecyclerView的信息。在适配器内部,您将看到以下内容:

@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

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


getChildAt()的问题在于,元素的顺序可能不超过5个元素:0、5、4、3、2、1(子计数主要是> =可见项的计数)。因此,我尝试通过getGlobalVisibleRect获取元素的顺序。
2014年

您的实际要求是什么,以实际顺序获取可见​​的子级(屏幕绑定范围内的子级)?
Sreejith B Naick 2014年

现在我想知道哪个元素在中心,以后我可能也对边界感兴趣。
2014年

1
您只会从中获得可见的项目recyclerView.getChildAt(),这就是通常的RecyclerView工作方式。RecyclerView将尝试仅保留当前可见的少数子视图(即,在屏幕范围内,而不是“已消失”,“不可见”),并尝试在用户滚动时回收这些视图。
Sreejith B Naick

6
查看visibleChild = recyclerView.getChildAt(0); int positionOfChild = recyclerView.getChildAdapterPosition(visibleChild);
Kevin Lee


4

附录

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

似乎回收站视图具有固定的高度,并且在扩展工具栏时,回收站向下移动,部分移出了屏幕。结果,所提出的功能的结果太高。示例:告诉最后一个可见项目是#9,但实际上,项目#7是屏幕上的最后一个项目。

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


没错,但这就是折叠工具栏的工作方式。一年前,我停止开发Android Apps,但我可以记住这一事实。
休息

3

为此StaggeredGridLayoutManager

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

并获得可见的项目视图:

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

请记住检查它是否为空。


你是什​​么意思“检查是否为空”?怎么检查?
tmm1

viewsIds是一个数组,它可能为空。
道格拉斯·纳西夫
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.