Flutter列表滑动曝光埋点,支持SliverList、SliverGrid

flutter_sliver_tracker

GitHub连接

滑动曝光埋点框架,支持SliverList、SliverGrid

什么是滑动曝光埋点

滑动曝光埋点用于滑动列表组件中的模块曝光,例如Flutter中的SliverListSliverGrid。 当SliverList中的某一个行(或列)移动到ViewPort中,并且显示比例超过一定阈值时,我们把这个事件记为一次滑动曝光事件。

当然我们对滑动曝光有一些额外的要求:

  • 需要滑出一定比例的时候才出发曝光(已实现)
  • 滑动速度快时不触发曝光事件(需要throttle)
  • 滑出视野的模块,再次滑入视野时需要再次上报(已实现)
  • 模块在视野中上下反复移动只触发一次曝光(还未实现)

运行Demo

图片名称

  • 克隆代码到本地: git clone git@github.com:SBDavid/flutter_sliver_tracker.git
  • 切换工作路径: cd flutter_sliver_tracker/example/
  • 启动模拟器
  • 运行: flutter run

内部原理

滑动曝光的核心难点是计算组件的露出比例。也是说我们需要知道ListView中的组件的总高度当前显示高度。 这两个高度做除法就可以得出比例。

组件总高度

组件的总高度可以在renderObject中获取。我们可以获取renderObject下的size属性,其中包含了组件的长宽。

当前显示高度

显示高度可以从SliverGeometry.paintExtent中获取。

使用文档

1. 安装

dependencies:
  flutter_sliver_tracker: ^1.0.0
复制代码

2. 引用插件

import 'package:xm_sliver_listener/flutter_sliver_tracker.dart';
复制代码

3. 发送滑动埋点事件

3.1 通过ScrollViewListener捕获滚动事件,ScrollViewListener必须包裹在CustomScrollView之上。

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // 通过ScrollViewListener捕获滚动事件
      body: ScrollViewListener(
        child: CustomScrollView(
          slivers: <Widget>[
          ],
        ),
      ),
    );
  }
}
复制代码

3.2 在SliverToBoxAdapter中监听滚动停止事件,并计算显示比例

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // 通过ScrollViewListener捕获滚动事件
      body: ScrollViewListener(
        child: CustomScrollView(
          slivers: <Widget>[
            SliverToBoxAdapter(
              // 监听停止事件,如果在页面上展示比例,可以自行setState
              child: SliverEndScrollListener(
                onScrollInit: (SliverConstraints constraints, SliverGeometry geometry) {
                  // 显示高度 / sliver高度
                  Fluttertoast.showToast(msg: "展示比例:${geometry.paintExtent / geometry.scrollExtent}");
                },
                onScrollEnd: (ScrollEndNotification notification,
                    SliverConstraints constraints,
                    SliverGeometry geometry) {
                  Fluttertoast.showToast(msg: "展示比例:${geometry.paintExtent / geometry.scrollExtent}");
                },
                child: Container(
                  height: 300,
                  color: Colors.amber,
                 
                  ),
                ),
            ),
          ],
        ),
      ),
    );
  }
}
复制代码

3.3 在SliverListSliverGrid中监听滚动停止事件,并计算显示比例

  • itemLength:列表项布局高度
  • displayedLength:列表项展示高度
  • 如果需要在widget中显示高度,可以自行setState
class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // 通过ScrollViewListener捕获滚动事件
      body: ScrollViewListener(
        child: CustomScrollView(
          slivers: <Widget>[
            SliverList(
              delegate: SliverChildBuilderDelegate(
                (BuildContext context, int index) {
                  // 监听滚动停止
                  return SliverMultiBoxScrollEndListener(
                    debounce: 1000,
                    child: Container(
                      height: 300,
                      color: Colors.redAccent,
                      child: Center(
                        child: Text("SliverList Item", style: TextStyle(fontSize: 30, color: Colors.white))
                      ),
                    ),
                    onScrollInit: (double itemLength, double displayedLength) {
                      Fluttertoast.showToast(msg: "显示高度:${displayedLength}");
                    },
                    onScrollEnd: (double itemLength, double displayedLength) {
                      Fluttertoast.showToast(msg: "显示高度:${displayedLength}");
                    },
                  );
                },
                childCount: 1
              ),
            ),
          ],
        ),
      ),
    );
  }
}
复制代码

3.4 在SliverListSliverGrid中监听滚动更新事件,并计算显示比例

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      // 通过ScrollViewListener捕获滚动事件
      body: ScrollViewListener(
        child: CustomScrollView(
          slivers: <Widget>[
            SliverList(
              delegate: SliverChildBuilderDelegate(
                      (BuildContext context, int index) {
                // 监听滚动更新事件
                return SliverMultiBoxScrollUpdateListener(
                  onScrollInit: (double percent) {
                    // percent 列表项显示比例
                  },
                  onScrollUpdate: (double percent) {
                    // percent 列表项显示比例
                  },
                  debounce: 1000,
                  // percent 列表项显示比例
                  builder: (BuildContext context, double percent) {
                    return Container(
                      height: 200,
                      color: Colors.amber.withAlpha((percent * 255).toInt()),
                      child: Center(
                          child: Text("SliverList Item Percent ${percent.toStringAsFixed(2)}", style: TextStyle(fontSize: 30, color: Colors.white))
                      ),
                    );
                  },
                );
              },
              childCount: 6
              ),
            ),
          ],
        ),
      ),
    );
  }
}


作者:SBDavid
链接:https://juejin.im/post/5e35276c6fb9a02fc90e3dfc
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Flutter中可以使用GestureDetector和Animation结合来实现左右滑动出现按钮的效果。 首先,使用GestureDetector来监听滑动手势。可以通过设置onHorizontalDragUpdate来获取滑动的偏移量,并通过动画控制器控制按钮的出现与隐藏。在动画控制器的动画更新里,可以通过setState来改变按钮的位置。 以下是一个示例代码: ```dart import 'package:flutter/material.dart'; class SlideButtonPage extends StatefulWidget { @override _SlideButtonPageState createState() => _SlideButtonPageState(); } class _SlideButtonPageState extends State<SlideButtonPage> with SingleTickerProviderStateMixin { Animation<double> _animation; AnimationController _animationController; double _dragOffset = 0.0; double _buttonWidth = 80.0; double _maxSlideWidth = 120.0; @override void initState() { super.initState(); _animationController = AnimationController(duration: Duration(milliseconds: 200), vsync: this); _animation = Tween<double>( begin: _buttonWidth, end: 0.0, ).animate(_animationController) ..addListener(() { setState(() {}); }); } @override void dispose() { _animationController.dispose(); super.dispose(); } void _handleDragUpdate(DragUpdateDetails details) { _dragOffset += details.delta.dx; if (_dragOffset < 0.0) { _dragOffset = 0.0; } else if (_dragOffset > _maxSlideWidth) { _dragOffset = _maxSlideWidth; } _animationController.value = _dragOffset / _maxSlideWidth; } void _handleDragEnd(DragEndDetails details) { if (_animationController.value < 0.5) { _animationController.reverse(); } else { _animationController.forward(); } } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Slide Button'), ), body: GestureDetector( onHorizontalDragUpdate: _handleDragUpdate, onHorizontalDragEnd: _handleDragEnd, child: Stack( children: [ Container( width: MediaQuery.of(context).size.width, height: 100.0, color: Colors.grey[300], ), Positioned( top: 0.0, right: _animation.value - _buttonWidth, child: Container( width: _buttonWidth, height: 100.0, color: Colors.red, child: Icon( Icons.delete, color: Colors.white, ), ), ), ], ), ), ); } } ``` 在这个示例中,我们使用Stack来实现按钮的叠加效果,一个是背景容器,另一个是通过Positioned来控制位置的按钮容器。通过计算dragOffset的值来更新按钮的位置,在松开手指时根据动画控制器的值来决定是否展示按钮。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值