背景
电商类APP列表页,用户上下滑动,列表页中的item显示在屏幕中,此时数据分析上来看,item的显示(比如滑动停止或者停止1s),都认为是一次数据的曝光,此时会根据曝光率(曝光率= 点击量 / 曝光量)来分析用户(比如用户的喜好推荐数据的统计)
监听View可见性
UITableView,UIColelctionView
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath API_AVAILABLE(ios(6.0));
- (void)collectionView:(UICollectionView *)collectionView willDisplayCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath API_AVAILABLE(ios(8.0));
- (void)collectionView:(UICollectionView *)collectionView didEndDisplayingCell:(UICollectionViewCell *)cell forItemAtIndexPath:(NSIndexPath *)indexPath;
willDisplayCell 和cellForRowAtIndexPath对比:
先执行cellForRowAtIndexPath再执行willDisplayCell,cellForRowAtIndexPath一半用于数据填充,willDisplayCell可用于自定义分割线,对于实时性的埋点曝光统计,可用willDisplayCell方法实现。
UIScrollVIew
UIScrollVIew 停止滚动的类型分为三种:
- 快速滚动,自然停止
- 快速滚动,手势介入停止
- 快速滚动停止(上两种结合情况)
// 自然停止
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView {
BOOL scrollToScrollStop = !scrollView.tracking && !scrollView.dragging && !scrollView.decelerating;
if (scrollToScrollStop) {
[self scrollViewDidEndScroll];
}
}
// 手势介入停止
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
if (!decelerate) {
// 停止类型3
BOOL dragToDragStop = scrollView.tracking && !scrollView.dragging && !scrollView.decelerating;
if (dragToDragStop) {
[self scrollViewDidEndScroll];
}
}
}
// 滚动停止事件
- (void)scrollViewDidEndScroll {
NSLog(@"监测到滚动停止了");
}
对于滑动停止这种条件性的曝光埋点,可用UIScrollVIew滑动停止的方法实现。
曝光逻辑条件分析
对于条件性曝光埋点,采用UIScrollVIew滑动停止方法实现,具体曝光条件是
- 刚进入页面时(加载新页面)
(可见且>=50%,上报可见) - 滑动停止时
( 可见且>=50%,上报可见 )
上报时机就是监听滚动停止事件,做相关的埋点上传处理
可见性>=50%判断
获取tableview的可见cell
- (NSArray*)visibleCells;
返回一个UITableviewcell的数组。
- (NSArray*)indexPathsForVisibleRows;
返回一个NSIndexPath的数组
- (CGRect)rectForRowAtIndexPath:(NSIndexPath*)indexPath;
CGRect cellR = [tableView rectForRowAtIndexPath:indx];
获取对应NSIndexPath的CGRect
这里可以根据获取NSIndexPath的数组的cell,获取对应的NSIndexPath的CGRect,这里我们的列表是竖着滑动,我们只获取cell的origin.y和size.height这两个属性
视图讲解分析
手机显示原型图根据上面视图,cell可见可分为三类:
- 屏幕上方显示的部分
- 屏幕中间全部显示的部分
- 屏幕下方显示的部分
坐标系转换:
currentRect = tableView.convert(previousCellRect, to: self.view.superview)
计算相对于屏幕本身的rect属性
屏幕上方部分计算规则:
- 第一种计算:
超出屏幕部分 = currentRect.origin.y的绝对值
判断:超出屏幕部分 / currentRect.size.height < 0.5 - 第二种计算:
留在屏幕的部分 = currentRect.origin.y + currentRect.size.height
判断:留在屏幕的部分 / currentRect.size.height >= 0.5
屏幕下方部分计算规则:
- 第一种计算:
超出屏幕的部分 = (currentRect.origin.y + currentRect.size.height)- 屏幕的高
判断:超出屏幕部分 / currentRect.size.height < 0.5 - 留在屏幕的部分 = currentRect.size.height - 超出屏幕的部分
判断:留在屏幕的部分 / currentRect.size.height >= 0.5
屏幕中间的部分:
- 显示100%,通过判断直接埋点上报
具体代码如下(swift写法):
// 相关位置添加如下代码,循环遍历可见cell数组
for indexPath in tableView.indexPathsForVisibleRows ?? [] {
self.exposureBuriedPoint(indexPath: indexPath)
}
// 曝光上报埋点,显示超过50%进行上报
func exposureBuriedPoint(indexPath: IndexPath) {
let previousCellRect = tableView.rectForRow(at: indexPath)
if previousCellRect.isEmpty == false {
let cellRect = tableView.convert(previousCellRect, to: self.view.superview)
let currentY = cellRect.origin.y + cellRect.size.height
if cellRect.origin.y < 0 {
let percentage = currentY / cellRect.size.height
if percentage >= 0.5 {
// 上报埋点
// ********* 进行曝光埋点相关统计处理代码写在这里 *********
}
} else {
if currentY > ScreenHeight {
let percentage = (currentY - ScreenHeight) / cellRect.size.height
if percentage < 0.5 {
// 上报埋点
// ********* 进行曝光埋点相关统计处理代码写在这里 *********
}
} else {
// 上报埋点
// ********* 进行曝光埋点相关统计处理代码写在这里 *********
}
}
}
}
网友评论