欢迎重视微信大众号:FSA全栈举动

系列文章

开源库: flutter_scrollview_observer

  1. Flutter – 获取ListView当时正在显现的Widget信息
  2. Flutter – 列表翻滚定位超强辅佐库,墙裂引荐!
  3. Flutter – 快速完成谈天会话列表的作用,完美
  4. Flutter – 船新升级支撑调查第三方构建的翻滚视图
  5. Flutter – 瀑布流交替播映视频
  6. Flutter – IM保持消息位置大升级(支撑ChatGPT生成式消息)
  7. Flutter – 翻滚视图中的表单防遮挡
  8. Flutter – 秒杀1/2曝光核算

一、概述

在很多的曝光核算核算方法中,有这么一种特别的,名为 1/2 曝光核算的核算方法,望文生义就是模块显露的大小超过本身大小的 50% 时,需求触发一次核算,并记载起来避免被重复核算,当少于 50% 时会将曝光记载进行重置。

一般会用于核算在列表页中投放的广告和详情页中某些广告模块的曝光。

二、解决计划

要实时监测并核算来得到当时一切 item 的本身显现占比仍是比较麻烦的,所以遍及咱们会优先去找和运用已存在的解决计划。

那想必咱们脑海中第一个想到的便是谷歌自家的 visibility_detector,这个库也的确很好用,常规场景下呢我也比较引荐咱们运用它的,由于它真的太方便了!不过我所遇到的一种场景它却无法担任,那就是在 CustomScrollView 中存在 SliverPersistentHeader 的状况,它的核算成果会不精确,如下所示。

Flutter - 秒杀1/2曝光统计

注意看蓝色的 Middle Sliver 视图,当它刚被 AppBar 挡住时本身显现占比仍是 1,直到超出了屏幕的上方才开始发生变化,当被 AppBar 彻底遮挡时值为 0.58~

不过这里我着重介绍一下另一个计划,那就是运用我这个库(flutter_scrollview_observer) 去快速获取 item 本身显现占比,而且不会有上述的 bug

三、实战

ListView 为例,代码如下:

final observerController = ListObserverController();
ListViewObserver(
  child: _buildListView(),
  // 不进行对比,直接把成果返出来
  triggerOnObserveType: ObserverTriggerOnObserveType.directly,
  controller: observerController,
  onObserve: (resultModel) {
    // 从调查成果中拿到正在展现的一切 item 的数据
    final models = resultModel.displayingChildModelList;
    // 取出一切下标
    final indexList = models.map((e) => e.index).toList();
    // 取出一切 item 的本身显现占比
    final displayPercentageList =
        models.map((e) => e.displayPercentage).toList();
    debugPrint('index -- $indexList -- $displayPercentageList');
  },

是的,拿到一切的 item 的本身显现占比就是这么简单,经过运用对应的 WidgetObserver 去对翻滚视图进行调查就可以了。

每次翻滚的时分就会直接回来调查成果,假如需求在不翻滚的时分也能进行一次调查,可以调用如下方法

observerController.dispatchOnceObserve();

四、核算逻辑

上面你现已能拿到本身显现占比的数据,那接下来就可以做是否触发曝光的逻辑判断了,这个比较业务化,所以这里直接给出我的代码吧,供参加运用

import 'package:scrollview_observer/scrollview_observer.dart';
mixin VisibilityExposureMixin {
  // 记载 item 已曝光的 Map
  Map<dynamic, bool> exposureRecordMap = {};
  /// 重置一切 item 的曝光记载
  resetExposureRecordMap() {
    exposureRecordMap.clear();
  }
  /// 处理翻滚视图中 item 的曝光
  /// 
  /// [resultModel] 监听成果(基类是 ObserveModel, 传 onObserve 回调中的值,或 onObserveAll 中依据 BuildContext 取出来的值)
  /// [toExposeDisplayPercent] 当本身显现占比超过该值时视为曝光且记载起来,否则重置曝光记载
  /// [recordKeyCallback] 回来用于记载 item 已曝光的 key,不完成则运用下标
  /// [needExposeCallback] 用于确定对应下标的 item 是否参加曝光核算逻辑,不完成则为 true
  /// [toExposeCallback] 满意曝光条件后的回调
  handleExposure({
    required dynamic resultModel,
    double toExposeDisplayPercent = 0.5,
    dynamic Function(int index)? recordKeyCallback,
    bool Function(int index)? needExposeCallback,
    required Function(int index) toExposeCallback,
  }) {
    List<ObserveDisplayingChildModelMixin> displayingChildModelList = [];
    if (resultModel is ListViewObserveModel) {
      displayingChildModelList = resultModel.displayingChildModelList;
    } else if (resultModel is GridViewObserveModel) {
      displayingChildModelList = resultModel.displayingChildModelList;
    }
    for (var displayingChildModel in displayingChildModelList) {
      final index = displayingChildModel.index;
      final recordKey = recordKeyCallback?.call(index) ?? index;
      // 让外部告知咱们 index 对应的 item 是否需求参加曝光核算逻辑
      final needExpose = needExposeCallback?.call(index) ?? true;
      if (!needExpose) continue;
      // debugPrint('item : $index - ${displayingChildModel.displayPercentage}');
      // 判断 item 本身显现占比是否超过 [toExposeDisplayPercent]
      if (displayingChildModel.displayPercentage < toExposeDisplayPercent) {
        // 不满意曝光条件,重置曝光记载
        exposureRecordMap[recordKey] = false;
      } else {
        // 满意暴露条件
        final haveExposure = exposureRecordMap[recordKey] ?? false;
        if (haveExposure) continue;
        toExposeCallback(index);
        exposureRecordMap[recordKey] = true;
      }
    }
  }
}

逻辑:

  1. 达到 1/2 后触发曝光核算,并记载起来,防触发屡次恳求
  2. 小于 1/2 时重置当时 item 的曝光记载

运用:

混入 VisibilityExposureMixin

class _VisibilityListViewPageState extends State<VisibilityListViewPage>
    with VisibilityExposureMixin {
  ...
}

onObserve 中调用 handleExposure 方法

onObserve: (resultModel) {
  handleExposure(
    resultModel: resultModel,
    needExposeCallback: (index) {
      // 只有下标为 6 的 item 需求核算是否曝光
      return index == 6;
    },
    toExposeCallback: (index) {
      // 满意条件,可以上报曝光了
      debugPrint('Exposure -- $index');
    },
  );
},

终究看下作用吧,注意看赤色视图和控制台的输出

曝光左下角 ListView 中下标为 6 的赤色 item

曝光左下角 SliverGrid 中下标为 6 的紫色 item

Flutter - 秒杀1/2曝光统计

Demo链接:visibility_demo

五、最终

经过上述示例的解说,相信你对 scrollview_observer 的运用又愈加清楚,假如你也觉得这个库好用,请不惜给个 Star

GitHub: github.com/LinXunFeng/…

假如文章对您有所帮助, 请不惜点击重视一下我的微信大众号:FSA全栈举动, 这将是对我最大的鼓励. 大众号不仅有 iOS 技术,还有 AndroidFlutterPython 等文章, 可能有你想要了解的技术知识点哦~