在RecyclerView中获取可见项目

时间:2014-07-28 06:00:47

标签: android android-recyclerview

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

有人有什么想法吗?

10 个答案:

答案 0 :(得分:517)

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

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

例如:

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

对于LinearLayoutManager,first / last取决于适配器的排序。不要查询来自RecyclerView的孩子; LayoutManager可能更喜欢布置比缓存可见的更多项目。

答案 1 :(得分:7)

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

关键是来自LayoutManager的方法 isViewPartiallyVisible

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

答案 2 :(得分:4)

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

答案 3 :(得分:2)

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;

请记住检查它是否为空。

答案 4 :(得分:2)

可以使用以下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

答案 5 :(得分:0)

附录

建议的函数 findLast ... Position()在工具栏折叠时展开的工具栏上不能正常工作。

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

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

答案 6 :(得分:0)

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

@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 :(得分:0)

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

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

答案 8 :(得分:0)

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

import React from "react";
import ReactDOM from "react-dom";
import "react-app-polyfill/ie11";
import "core-js/stable";
import "regenerator-runtime/runtime";
import "polyfill-array-includes";
import Joyride from "react-joyride";

const CustomTooltip = ({
  index,
  size,
  step,
  skipProps,
  primaryProps,
  tooltipProps,
  isLastStep
}) => (
  <div {...tooltipProps} style={{ background: "blue", padding: "20px" }}>
    <button {...skipProps}>Skip Tour</button>
    <button {...primaryProps}>{isLastStep ? "Close" : "Next"}</button>
  </div>
);

const App = () => {
  const steps = [
    {
      target: ".a",
      title: "",
      content: "a",
      placement: "bottom-start",
      disableBeacon: true
    },
    {
      target: ".b",
      title: "",
      content: "b",
      placement: "bottom-start",
      disableBeacon: true
    },
    {
      target: ".c",
      title: "",
      content: "c",
      placement: "bottom-start",
      disableBeacon: true
    }
  ];

  return (
    <div>
      <div style={{ background: "yellow" }} className={"a"}>
        hey
      </div>
      <div style={{ background: "green" }} className={"b"}>
        hey
      </div>
      <div style={{ background: "red" }} className={"c"}>
        hey
      </div>
      <Joyride steps={steps} tooltipComponent={CustomTooltip} />
    </div>
  );
};

ReactDOM.render(<App />, document.getElementById("root"));

答案 9 :(得分:0)

我希望下面的代码可以帮助某人定义上面的 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


        }
    });