Flutter之事件处理

本文详细探讨了Flutter的事件处理,从事件传递开始,包括Down事件处理和其他事件处理,展示了Flutter事件处理机制与前端事件冒泡的相似性。接着,介绍了Flutter的事件拦截,利用AbsorbPointer和IgnorePointer实现事件拦截,并给出应用实例。此外,还讲解了GestureDetector手势处理的使用和实现原理,为开发者提供了一种快速实现点击、滑动等手势功能的方式。
摘要由CSDN通过智能技术生成

在学习flutter的时候突然想到,flutter既然不像其他跨平台框架那样采用系统原生渲染,那么flutter就应该拥有自己的事件处理机制。本着好奇的心理,来对flutter的事件处理机制一窥究竟。

1、flutter事件传递

事件都是由硬件收集起来的,然后传递给软件。那么在flutter中,事件的源头在哪尼?

经过分析源码可以发现。在类window中,flutter通过方法onPointerDataPacket来接收硬件传递过来的事件,也就是说该方法是flutter接收事件的源头,而该方法是在类GestureBinding初始化的时候设置的。所以在类GestureBinding的方法_handlePointerDataPacket中开始处理事件。

mixin GestureBinding on BindingBase implements HitTestable, HitTestDispatcher, HitTestTarget {
  @override
  void initInstances() {
    super.initInstances();
    _instance = this;
    //_handlePointerDataPacket(是一个私有方法)接收系统传递过来的事件,
    window.onPointerDataPacket = _handlePointerDataPacket;
  }

  ...

  //一个FIFO的双端队列,用来存储事件
  final Queue<PointerEvent> _pendingPointerEvents = Queue<PointerEvent>();

  void _handlePointerDataPacket(ui.PointerDataPacket packet) {
    //这里做了以下两个操作
    //1、将pointer数据转换为逻辑像素,从而隔离真实设备。
    //2、将转换后的数据加入到FIFO双端队列中
    _pendingPointerEvents.addAll(PointerEventConverter.expand(packet.data, window.devicePixelRatio));
    if (!locked){
      //开始处理事件
      _flushPointerEventQueue();
    }
  }

  ...

  void _flushPointerEventQueue() {
    assert(!locked);
    //如果队列中有数据,就处理
    while (_pendingPointerEvents.isNotEmpty)
      _handlePointerEvent(_pendingPointerEvents.removeFirst());
  }

  ...
  
  final Map<int, HitTestResult> _hitTests = <int, HitTestResult>{};
  
  void _handlePointerEvent(PointerEvent event) {
    assert(!locked);
    HitTestResult hitTestResult;
    //如果是Down事件
    if (event is PointerDownEvent) {
      assert(!_hitTests.containsKey(event.pointer));
      hitTestResult = HitTestResult();
      //将事件要经过的所有Widget添加到一个集合中
      hitTest(hitTestResult, event.position);
      _hitTests[event.pointer] = hitTestResult;
      assert(() {
        if (debugPrintHitTestResults)
          debugPrint('$event: $hitTestResult');
        return true;
      }());
    } else if (event is PointerUpEvent || event is PointerCancelEvent) {
      hitTestResult = _hitTests.remove(event.pointer);
    } else if (event.down) {
      //如果是move事件
      hitTestResult = _hitTests[event.pointer];
    }
    assert(() {
      if (debugPrintMouseHoverEvents && event is PointerHoverEvent)
        debugPrint('$event');
      return true;
    }());
    if (hitTestResult != null ||
        event is PointerHoverEvent ||
        event is PointerAddedEvent ||
        event is PointerRemovedEvent) {
      //分发事件
      dispatchEvent(event, hitTestResult);
    }
  }

  @override // from HitTestable
  void hitTest(HitTestResult result, Offset position) {
    result.add(HitTestEntry(this));
  }

  //事件的分发
  @override // from HitTestDispatcher
  void dispatchEvent(PointerEvent event, HitTestResult hitTestResult) {
    assert(!locked);
    ...
    for (HitTestEntry entry in hitTestResult.path) {
      try {
        //分发给子Widget处理
        entry.target.handleEvent(event, entry);
      } catch (exception, stack) {
        ...
      }
    }
  }
  
  //
  @override // from HitTestTarget
  void handleEvent(PointerEvent event, HitTestEntry entry) {
    pointerRouter.route(event);
    if (event is PointerDownEvent) {
      gestureArena.close(event.pointer);
    } else if (event 
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Flutter 中,处理双击(double tap)事件通常涉及到处理 `GestureDetector` 或者更高级别的 ` GestureDetector.onTapDown`, `onTapUp` 和 `onTapCancel` 连接在一起。因为默认情况下,Flutter 并不会自动检测双击,所以我们需要自定义逻辑来识别两次快速的单击。 下面是一个基本的例子,展示了如何使用 `GestureDetector` 来实现双击事件: ```dart GestureDetector( onDoubleTap: () { // 当发生双击时,执行的回调函数 setState(() { // 更新状态或触发其他操作 }); }, onTap: () {}, // 单击事件,可选,但不是必需的 onTapDown: (_) { // 当按下触摸屏幕时,开始计数 _doubleTapCounter++; }, onTapUp: (_) { // 当释放触摸屏幕时,停止计数 if (_doubleTapCounter > 0) { _doubleTapCounter--; if (_doubleTapCounter == 0) { // 如果计数器归零,则表示发生了双击 onDoubleTap(); } } }, onTapCancel: (_) { // 取消计数 _doubleTapCounter = 0; }, ), ``` 在这个例子中,我们使用 `_doubleTapCounter` 记录触摸的次数。当用户第一次按下(`onTapDown`)时加一,当他们松开并且计数器大于零(即第二次按下)时,就认为是双击(`onTapUp`)。`onTapCancel` 用于清除计数器,以防用户的手指长时间停留在屏幕上。 注意,这只是一个基础示例,实际应用中可能还需要考虑边缘情况,比如手指移动太快导致计数错误。另外,对于一些设备,你可能需要禁用硬件双击手势,以免它们干扰用户的交互体验。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值