在RecyclerView中获取可见项目

我需要知道哪些元素目前显示在我的RecyclerView。ListViews上没有与OnScrollListener.onScroll(...)方法等价的方法。我试图工作与View.getGlobalVisibleRect(...),但黑客是太丑陋,并不总是工作太。

有人有什么想法吗?

266333 次浏览

你可以使用recyclerView.getChildAt()来获取每个可见的子视图,在适配器代码中对这些视图设置一些标记convertview.setTag(index)将帮助你将它与适配器数据关联起来。

第一个/最后一个可见子元素依赖于LayoutManager。 如果你正在使用LinearLayoutManagerGridLayoutManager,你可以使用

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

例如:

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

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

对于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;

记得检查它是否为空。

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

关键是LayoutManager中的isViewPartiallyVisible .方法。

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

下面的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

< p > 齿顶高: < br > < br > 建议的函数findLast…位置()在工具栏折叠而工具栏展开的情况下正确工作 回收器视图似乎有一个固定的高度,当工具栏展开时,回收器会向下移动,部分移出屏幕。因此,所提出的函数的结果过高。示例:最后一个可见的项目被告知是#9,但实际上项目#7是屏幕上的最后一个 这种行为也是为什么我的视图经常无法滚动到正确位置的原因,即scrolltopposition()没有正确工作(我最终以编程方式折叠工具栏)
对于那些在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"));
}
}
});
}
}

你可以找到recycle视图的第一个和最后一个可见的子视图,并检查你正在寻找的视图是否在范围内:

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")

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

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();
            

}
});

如果可见的项目位置与项目位置不同,吐司消息将显示在屏幕上。

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




}
});

对于那些在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()