我有一个 ListView 和 ArrayAdapter < CustomListViewItem > 设置为其适配器。我想跟踪每个 CustomListViewItem 项目的展示次数。
每当 ListView 项目进入视图时,都应计为一次展示。当它消失并再次出现时,展示次数就会增加。当用户滚动时,某些项目将消失在视图中,而某些项目将进入视图。我想跟踪进入视图和移出视图的项目。
我尝试过的:
我尝试过的一件事是为列表设置setOnScrollListener 查看并进行跟踪 onScroll(AbsListView视图,intfirstVisibleItem,intvisibleItemCount,inttotalItemCount)回调。
我可以使用 firstVisibleItem 和 visibleItemCount 来完成这项工作。 在文档中,它说这是在滚动完成时调用的。但当滚动缓慢时,它似乎会被调用很多次。可能在滚动的每个像素之后。这使得滚动非常滞后。
还有其他方法可以做到这一点吗?通过使用某种回调,当每个项目离开视图或进入视图时,都会调用该回调?
我在网上搜索了很多,没有看到任何与此类跟踪相关的帖子。
我找不到其他方法来做到这一点。所以,我优化了我已经在做的事情。我想我应该分享这个,因为它可能会帮助其他人。
我使用 onScroll() 的 firstVisibleItem 和 visibleItemCount 仅回调。我使用两个变量来保存先前 onScroll() 回调的信息。他们是:
prevVisibleStart 和 prevVisibleEnd
让我们举个例子来理解算法。 最初假设在第一个 onScroll() 之后
f第一个可见项 = 0 和 visibleItemCount = 3 => 最后的VisibleItem = 2
这些用于设置我之前的可见状态。
所以,prevVisibleStart = firstVisibleItem = 3 和 prevVisibleEnd = 第一个可见项 + 可见项计数 - 1 = 2
现在如果我向下滚动,我将永远拥有
firstVisibleItem >= prevVisibleStart 和 lastVisibleItem >= prevVisibleEnd
所以,如果之前的范围是 0 到 2。新的范围会有点像 1 到 3。因为,我已经考虑了 0 到 2 的印象。我只会将 3 视为新印象。原因是视图 1、2 仍然在视图中并且没有消失。因此,新印象不计入这些。这有效地给出了考虑展示次数的正确范围,并减少了检查范围。
同样,向上滚动也可以这样做。 假设当前可见项为2-4。 现在,向上滚动后,范围变为(例如)1-3。这意味着1已经进入视野。因此,计算此视图的展示次数。这样 onScroll() 中的操作次数显着减少。
示例代码如下
范围 [i-j) 被视为印象。
private static int prevVisibleStart=-1;
private static int prevVisibleEnd=-1;
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if(prevVisibleStart <= firstVisibleItem) {
// scroll down
i = Math.max(firstVisibleItem, prevVisibleEnd + 1);
j = firstVisibleItem + visibleItemCount;
} else {
// scroll up
i = firstVisibleItem;
j = Math.min(prevVisibleStart, firstVisibleItem + visibleItemCount);
}
prevVisibleStart = firstVisibleItem;
prevVisibleEnd = firstVisibleItem + visibleItemCount - 1;
// now can use [i-j) to update impressions
}
在适配器中定义回调
var onAttachView: ((position: Int) -> Unit)? = null
并在适配器的onViewAttachedToWindow方法中调用它
override fun onViewAttachedToWindow(holder: ViewHolder) {
super.onViewAttachedToWindow(holder)
onAttachView?.invoke(holder.bindingAdapterPosition)
}
如果您只想发送列表中项目的一次印象,您可以将报告的位置临时保存在视图模型或分析存储库中,然后根据您的会话策略将其清除。