【问题标题】:RecyclerView: find last visible item immediately after view createdRecyclerView:在视图创建后立即查找最后一个可见项目
【发布时间】:2015-07-10 05:44:21
【问题描述】:

以下方法有问题:

int firstVisibleItemPosition = gridLayoutManager.findFirstVisibleItemPosition();
int lastVisibleItemPosition = gridLayoutManager.findLastVisibleItemPosition();

我的目标:保存有关用户查看过哪些项目的分析数据。

为了做到这一点,我在两种不同的场景中调用了这个方法:

  • 每次滚动都转为“空闲”状态,并检查可见项目是什么。在这种情况下,我得到了预期的索引。

  • RecyclerView 对用户“可见”时。 现在这就是问题开始的时候。我希望当包含recyclerView 的片段通过onResume() 时,调用findLastVisibleItemPosition() 将返回可见项目。 但在这种情况下它返回 -1。 我猜这与 recyclerView + 适配器内部项目初始化相对于片段/活动生命周期的异步加载有关。

将此代码推迟几毫秒 - findLastVisibleItemPosition() 返回正确的索引。但我不想推迟使用处理程序+延迟可运行的硬编码,因为调度延迟可运行是我真正想做的解决方法:检测回收器视图何时完成充气并将所有视图绘制到屏幕上脚在里面..

所以我的问题基本上是:

  • 如何检测 RecyclerView 何时完成所有初始化/测量/膨胀和绘制它的子项进入屏幕? (在任何用户交互之前..)。

  • 是否有任何可靠的良好做法可以准确了解回收站视图中的哪些项目真正显示在屏幕上?

【问题讨论】:

  • 嗨,@Tal Kanel 在这篇文章之后你得到了任何可靠的答案吗?我有点面临类似的问题。
  • @hadez30:我的解决方案是运行代码检查来自 UI 线程上的处理程序发布的可运行文件中的第一个可见项目(不延迟..)。这就是为什么它在 UI 队列末尾执行的原因,根据我的经验,这是在视图已经附加到回收器视图之后发生的

标签: android android-layout android-adapter android-recyclerview


【解决方案1】:

配置更改呢?如果用户改变屏幕方向,可见项目也会改变。事实上,可见项会根据RecyclerView的状态、加载的数据、滚动位置和当前屏幕配置不断变化。

您可能做的最好的事情是创建一个不断跟踪可见项超集的类,方法是使其实现ItemDecoration 接口,每次在屏幕上重绘RecyclerView 时都会调用该接口,并具有该组件定期发送统计信息。您可以在配置更改时将其重新附加到新的 RecyclerView 实例(保留其状态)。

例如,这个组件可以跟踪最小和最大可见位置。起初,两者都是-1。然后在加载数据并在屏幕上显示第一个项目后,将再次调用ItemDecoration,第一个可见项目位置现在为 0,最后一个可见项目位置现在为 N。滚动后,值将再次更改.您只需保留 FirstVisibleItemPosition 的最小值和 LastVisibleItemPosition 的最大值即可获得超集。 X 秒后没有更改,或者如果用户从 Activity 导航回来,您将记录并发送这些数字。

【讨论】:

  • 一种类似的方法是跟踪对onBindViewHolder 的调用,以检查哪些项目已绑定(显示)并据此确定哪些项目未显示。
【解决方案2】:

使用OnChildAttachListener 检测回收商何时附加新的支架。使用延迟机制来发送正确的分析(\不是硬编码的延迟,而是这样的:

...
public void run(){
  removeCallbacks()
  postDelay(sendAnalytics(correctInformation),25);
}

25ms 延迟更可靠,然后将其附加到 onResume 任意。

【讨论】:

    【解决方案3】:

    至于回答你的第一个问题。我发现这个问题的最佳解决方案是在回收器视图上设置布局更改侦听器:

    recyclerView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
        @Override
        public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
            recyclerView.removeOnLayoutChangeListener(this); //remove layout change listener, you want need it anymore
            //do your work here
        }
    });
    

    关于第二个问题。您可以通过 getChildCount() 和 getChildAt(int) 来获取有关当前附加到 recyclerView 的子视图的信息,但这并不意味着它们在屏幕上可见(它们可能在屏幕外有点)。要检查它们是否可见,请参阅Android: how to check if a View inside of ScrollView is visible?

    【讨论】:

    • onLayoutChange() 是在视图本身更改它的尺寸时调用的,而不是在他的嵌套子项更改时调用。所以它永远不会与总是预定义高度和宽度的 recyclerView 一起工作
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-25
    • 1970-01-01
    • 1970-01-01
    • 2019-03-10
    相关资源
    最近更新 更多