310

我需要知道我的 RecyclerView 中当前显示了哪些元素。没有与OnScrollListener.onScroll(...)ListViews 上的方法等效的方法。我尝试使用View.getGlobalVisibleRect(...),但是那个 hack 太丑了,而且并不总是有效。

有人有什么想法吗?

4

11 回答 11

644

第一个/最后一个可见的孩子取决于LayoutManager. 如果你使用LinearLayoutManageror GridLayoutManager,你可以使用

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

例如:

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

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

于 2014-07-31T07:50:48.877 回答
23

对于那些在 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"));
                        }
                }
            });
        }
    }
于 2019-06-02T18:22:11.100 回答
20

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

关键是 LayoutManager 中的isViewPartiallyVisible方法。

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

于 2018-02-06T15:34:20.500 回答
9

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

于 2014-07-28T06:47:53.803 回答
8

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

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

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

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

于 2019-02-07T09:01:13.267 回答
8

附录

建议的函数findLast...Position()在工具栏展开时工具栏折叠的情况下无法正常工作。

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

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

于 2019-05-21T18:30:34.587 回答
5

为此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;

记得检查它是否为空。

于 2016-05-17T19:57:24.290 回答
5

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

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) recycler.getLayoutManager();
            int firstElementPosition = lManager.findFirstVisibleItemPosition();
            
        }
    });
于 2020-09-24T21:25:27.863 回答
3

您可以找到回收视图的第一个和最后一个可见子项,并检查您要查找的视图是否在范围内:

var visibleChild: View = rv.getChildAt(0)
val firstChild: Int = rv.getChildAdapterPosition(visibleChild)
visibleChild = rv.getChildAt(rv.childCount - 1)
val lastChild: Int = rv.getChildAdapterPosition(visibleChild)
println("first visible child is: $firstChild")
println("last visible child is: $lastChild")
于 2020-07-30T08:21:02.140 回答
2

对于那些在 Kotlin 中寻找答案的人 -

    fun getVisibleItem(recyclerView : RecyclerView) {
        recyclerView.addOnScrollListener(object: RecyclerView.OnScrollListener() {
            override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
                 if(newState == RecyclerView.SCROLL_STATE_IDLE) {
                     val index = (recyclerView.layoutManager.findFirstVisibleItemPosition
                     //use this index for any operation you want to perform on the item visible on screen. eg. log(arrayList[index])
                 }
            }
        })
    }

您可以根据您的用例探索其他获取位置的方法。

int findFirstCompletelyVisibleItemPosition()
int findLastVisibleItemPosition()
int findLastCompletelyVisibleItemPosition()
于 2021-10-19T16:21:07.383 回答
1

我希望下面的代码可以帮助某人定义int a上述方法。如果在项目位置吐司消息之前可见项目位置不同,将在屏幕上显示

myRecyclerview.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
            super.onScrollStateChanged(recyclerView, newState);

            LinearLayoutManager manager= (LinearLayoutManager) myRecyclerview.getLayoutManager();
            assert manager != null;
            int visiblePosition = manager.findLastCompletelyVisibleItemPosition();


            if(visiblePosition > -1&&a!=visiblePosition) {
                Toast.makeText(context,String.valueOf(visiblePosition),Toast.LENGTH_SHORT).show();
                //do something
                a=visiblePosition;

            }
        }

        @Override
        public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
            super.onScrolled(recyclerView, dx, dy);
            //Some code while the list is scrolling


        }
    });
于 2021-04-13T15:16:36.393 回答