Flutter在启动时(runApp)会进行一些洒水类的”粘合”,WidgetsFlutterBinding作为主类,需求粘合一系列的Binding,其中GestureBinding便是事情处理类;

GestureBinding是Flutter中办理手势事情的Binding,是Flutter Framework层处理事情的最起点;

GestureBinding实现了HitTestable, HitTestDispatcher, HitTestTarget,别离具有以下功用

  • hitTest射中测验
  • dispatchEvent事情分发
  • handleEvent处理事情()

成员变量

//触点路由,由手势辨认器注册,会把手势辨认器的pointer和handleEvent存入
//以便在GestureBinding.handleEvent调用
final PointerRouter pointerRouter = PointerRouter();
//手势竞技场办理者,办理竞技场们的相关操作
final GestureArenaManager gestureArena = GestureArenaManager();
//hitTest列表,里边存储了被射中测验成员
final Map<int, HitTestResult> _hitTests = <int, HitTestResult>{};

GestureBinding在_handlePointerDataPacket办法接收有Engine层传递过来的触点数据,经过数据包装转换为Framework层可处理的数据:PointerAddedEvent、PointerCancelEvent、PointerDownEvent、PointerMoveEvent、PointerUpEvent等等,随后在_handlePointerEventImmediately办法中进行射中测验和事情分发;

手指按下

当手指按下时,接收到的事情类型是PointerDownEvent

首先是射中测验

当事情类型是event is PointerDownEvent || event is PointerSignalEvent || event is PointerHoverEvent会进行新的射中测验,射中测验相关请看这,得到射中测验列表后,开始调用dispatchEvent进行事情分发。

void _handlePointerEventImmediately(PointerEvent event) {
  HitTestResult? hitTestResult;
  if (event is PointerDownEvent || event is PointerSignalEvent || event is PointerHoverEvent) {
    assert(!_hitTests.containsKey(event.pointer));
    hitTestResult = HitTestResult();
    hitTest(hitTestResult, event.position);
    if (event is PointerDownEvent) {
      _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) {
    //当前事情是按下状态,重用hitTest成果
    hitTestResult = _hitTests[event.pointer];
  }
  if (hitTestResult != null ||
      event is PointerAddedEvent ||
      event is PointerRemovedEvent) {
    assert(event.position != null);
    dispatchEvent(event, hitTestResult);
  }
}

事情分发

事情分发的目的是调用射中对象的handleEvent办法以处理相关逻辑,比如咱们熟知的Listener组件,它做的事便是回调相关办法,比如按下时Listener会回调onPointerDown

## GestureBinding ##
@override // from HitTestDispatcher
void dispatchEvent(PointerEvent event, HitTestResult? hitTestResult) {
  assert(!locked);
  if (hitTestResult == null) {
    assert(event is PointerAddedEvent || event is PointerRemovedEvent);
    try {
      pointerRouter.route(event);
    } catch (exception, stack) {
      ...
    }
    return;
  }
  for (final HitTestEntry entry in hitTestResult.path) {
    try {
      entry.target.handleEvent(event.transformed(entry.transform), entry);
    } catch (exception, stack) {
      ...
    }
  }
}
## Listener ##
@override
void handleEvent(PointerEvent event, HitTestEntry entry) {
  assert(debugHandleEvent(event, entry));
  if (event is PointerDownEvent)
    return onPointerDown?.call(event);
  if (event is PointerMoveEvent)
    return onPointerMove?.call(event);
  if (event is PointerUpEvent)
    return onPointerUp?.call(event);
  if (event is PointerHoverEvent)
    return onPointerHover?.call(event);
  if (event is PointerCancelEvent)
    return onPointerCancel?.call(event);
  if (event is PointerSignalEvent)
    return onPointerSignal?.call(event);
}

咱们知道射中测验最终会把GestrueBinding本身加入到列表中,所以最终也会履行GestrueBinding的handleEvent办法

handleEvent

GestrueBinding.handleEvent是处理手势辨认器相关的逻辑,pointerRouter.route(event)调用了辨认器的handleEvent办法(需求提早进行触点注册),随后的是竞技场的相关处理;可以看这儿了解手势辨认器;

## GestrueBinding ##
@override // from HitTestTarget
void handleEvent(PointerEvent event, HitTestEntry entry) {
  pointerRouter.route(event);
  if (event is PointerDownEvent) {
    gestureArena.close(event.pointer);
  } else if (event is PointerUpEvent) {
    gestureArena.sweep(event.pointer);
  } else if (event is PointerSignalEvent) {
    pointerSignalResolver.resolve(event);
  }
}

手指抬起,

手指抬起会重用之前hitTest成果,并不会重新hitTest,如果是Listener组件,则会回调PointerUpEvent