{"id":20839110,"url":"https://github.com/sbdavid/flutter_sliver_tracker","last_synced_at":"2025-08-25T00:15:23.796Z","repository":{"id":49978567,"uuid":"228608750","full_name":"SBDavid/flutter_sliver_tracker","owner":"SBDavid","description":"flutter滑动曝光埋点框架，支持SliverList、SliverGrid","archived":false,"fork":false,"pushed_at":"2021-06-07T06:34:34.000Z","size":2935,"stargazers_count":45,"open_issues_count":2,"forks_count":10,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-05-08T21:35:27.332Z","etag":null,"topics":["flutter","gridview","listview"],"latest_commit_sha":null,"homepage":null,"language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-2-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SBDavid.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-12-17T12:10:37.000Z","updated_at":"2025-04-24T02:20:36.000Z","dependencies_parsed_at":"2022-09-09T10:50:13.543Z","dependency_job_id":null,"html_url":"https://github.com/SBDavid/flutter_sliver_tracker","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/SBDavid/flutter_sliver_tracker","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SBDavid%2Fflutter_sliver_tracker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SBDavid%2Fflutter_sliver_tracker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SBDavid%2Fflutter_sliver_tracker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SBDavid%2Fflutter_sliver_tracker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SBDavid","download_url":"https://codeload.github.com/SBDavid/flutter_sliver_tracker/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SBDavid%2Fflutter_sliver_tracker/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271983714,"owners_count":24853810,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-24T02:00:11.135Z","response_time":111,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["flutter","gridview","listview"],"created_at":"2024-11-18T01:12:22.610Z","updated_at":"2025-08-25T00:15:23.713Z","avatar_url":"https://github.com/SBDavid.png","language":"Dart","funding_links":[],"categories":[],"sub_categories":[],"readme":"# flutter_sliver_tracker\n\n滑动曝光埋点框架，支持SliverList、SliverGrid，以及嵌套的情况（详见example2/SliverMultiBoxScrollListenerDebounceDemo）\n\n## 什么是滑动曝光埋点\n\n滑动曝光埋点用于滑动列表组件中的模块曝光，例如Flutter中的`SliverList`、`SliverGrid`。\n当`SliverList`中的某一个行（或列）移动到`ViewPort`中，并且显示比例超过一定阈值时，我们把这个事件记为一次滑动曝光事件。\n\n当然我们对滑动曝光有一些额外的要求：\n- 需要滑出一定比例的时候才出发曝光（已实现）\n- 滑动速度快时不触发曝光事件（已实现）\n- 滑出视野的模块，再次滑入视野时需要再次上报（已实现）\n- 模块在视野中上下反复移动只触发一次曝光（已实现）\n- 嵌套情况：支持滑动组件相互全套（已实现）\n    - SliverMultiBoxScrollListener已支持嵌套\n    - SliverMultiBoxScrollListenerDebounce已支持嵌套\n    - SliverScrollListener不支持，请使用SliverMultiBoxScrollListener\n    - SliverScrollListenerDebounce不支持，请使用SliverMultiBoxScrollListenerDebounce\n    - 所有嵌套情况只测试过两层嵌套，理论上支持更多层。\n\n## 运行Demo\n\u003cimg src=\"https://raw.githubusercontent.com/SBDavid/flutter_sliver_tracker/master/demo.gif\" width=\"270\" height=\"480\" alt=\"图片名称\"\u003e\n\n- 克隆代码到本地: git clone git@github.com:SBDavid/flutter_sliver_tracker.git\n- 切换工作路径: cd flutter_sliver_tracker/example/\n- 启动模拟器\n- 运行: flutter run\n\n## 内部原理\n\n滑动曝光的核心难点是计算组件的露出比例。也是说我们需要知道`ListView`中的组件的`总高度`、`当前显示高度`。\n这两个高度做除法就可以得出比例。\n\n### 组件总高度\n组件的总高度可以在`renderObject`中获取。我们可以获取`renderObject`下的`size`属性，其中包含了组件的长宽。\n\n### 当前显示高度\n显示高度可以从`SliverGeometry.paintExtent`中获取。\n\n## 使用文档\n### 1. 安装\n\n```yaml\ndependencies:\n  flutter_sliver_tracker: ^1.0.0\n```\n\n### 2. 引用插件\n```dart\nimport 'package:xm_sliver_listener/flutter_sliver_tracker.dart';\n```\n\n### 3. 发送滑动埋点事件\n\n#### 3.1 通过`ScrollViewListener`捕获滚动事件，`ScrollViewListener`必须包裹在`CustomScrollView`之上。\n\n```dart\nclass _MyHomePageState extends State\u003cMyHomePage\u003e {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      // 通过ScrollViewListener捕获滚动事件\n      body: ScrollViewListener(\n        child: CustomScrollView(\n          slivers: \u003cWidget\u003e[\n          ],\n        ),\n      ),\n    );\n  }\n}\n```\n\n#### 3.2 在`SliverToBoxAdapter`中监听滚动停止事件，并计算显示比例\n```dart\nclass _MyHomePageState extends State\u003cMyHomePage\u003e {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      // 通过ScrollViewListener捕获滚动事件\n      body: ScrollViewListener(\n        child: CustomScrollView(\n          slivers: \u003cWidget\u003e[\n            SliverToBoxAdapter(\n              // 监听停止事件，如果在页面上展示比例，可以自行setState\n              child: SliverEndScrollListener(\n                onScrollInit: (SliverConstraints constraints, SliverGeometry geometry) {\n                  // 显示高度 / sliver高度\n                  Fluttertoast.showToast(msg: \"展示比例：${geometry.paintExtent / geometry.scrollExtent}\");\n                },\n                onScrollEnd: (ScrollEndNotification notification,\n                    SliverConstraints constraints,\n                    SliverGeometry geometry) {\n                  Fluttertoast.showToast(msg: \"展示比例：${geometry.paintExtent / geometry.scrollExtent}\");\n                },\n                child: Container(\n                  height: 300,\n                  color: Colors.amber,\n                 \n                  ),\n                ),\n            ),\n          ],\n        ),\n      ),\n    );\n  }\n}\n```\n\n#### 3.3 在`SliverList`和`SliverGrid`中监听滚动停止事件，并计算显示比例\n\n- itemLength：列表项布局高度\n- displayedLength：列表项展示高度\n- 如果需要在widget中显示高度，可以自行setState\n\n```dart\nclass _MyHomePageState extends State\u003cMyHomePage\u003e {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      // 通过ScrollViewListener捕获滚动事件\n      body: ScrollViewListener(\n        child: CustomScrollView(\n          slivers: \u003cWidget\u003e[\n            SliverList(\n              delegate: SliverChildBuilderDelegate(\n                (BuildContext context, int index) {\n                  // 监听滚动停止\n                  return SliverMultiBoxScrollEndListener(\n                    debounce: 1000,\n                    child: Container(\n                      height: 300,\n                      color: Colors.redAccent,\n                      child: Center(\n                        child: Text(\"SliverList Item\", style: TextStyle(fontSize: 30, color: Colors.white))\n                      ),\n                    ),\n                    onScrollInit: (double itemLength, double displayedLength) {\n                      Fluttertoast.showToast(msg: \"显示高度：${displayedLength}\");\n                    },\n                    onScrollEnd: (double itemLength, double displayedLength) {\n                      Fluttertoast.showToast(msg: \"显示高度：${displayedLength}\");\n                    },\n                  );\n                },\n                childCount: 1\n              ),\n            ),\n          ],\n        ),\n      ),\n    );\n  }\n}\n```\n\n#### 3.4 在`SliverList`和`SliverGrid`中监听滚动更新事件，并计算显示比例\n```dart\nclass _MyHomePageState extends State\u003cMyHomePage\u003e {\n  @override\n  Widget build(BuildContext context) {\n    return Scaffold(\n      // 通过ScrollViewListener捕获滚动事件\n      body: ScrollViewListener(\n        child: CustomScrollView(\n          slivers: \u003cWidget\u003e[\n            SliverList(\n              delegate: SliverChildBuilderDelegate(\n                      (BuildContext context, int index) {\n                // 监听滚动更新事件\n                return SliverMultiBoxScrollUpdateListener(\n                  onScrollInit: (double percent) {\n                    // percent 列表项显示比例\n                  },\n                  onScrollUpdate: (double percent) {\n                    // percent 列表项显示比例\n                  },\n                  debounce: 1000,\n                  // percent 列表项显示比例\n                  builder: (BuildContext context, double percent) {\n                    return Container(\n                      height: 200,\n                      color: Colors.amber.withAlpha((percent * 255).toInt()),\n                      child: Center(\n                          child: Text(\"SliverList Item Percent ${percent.toStringAsFixed(2)}\", style: TextStyle(fontSize: 30, color: Colors.white))\n                      ),\n                    );\n                  },\n                );\n              },\n              childCount: 6\n              ),\n            ),\n          ],\n        ),\n      ),\n    );\n  }\n}\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsbdavid%2Fflutter_sliver_tracker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsbdavid%2Fflutter_sliver_tracker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsbdavid%2Fflutter_sliver_tracker/lists"}