Flutter之事件处理

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

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在学习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 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值