还是以下面代码为入口去分析
runApp(
MaterialApp(
home: Scaffold(
appBar: AppBar(),
body: GestureDetector(
child: GestureDetector(
child: const Text("点击事件"),
onTap: () {
log.log("GestureDetector ---2");
},
),
onTap: () {
log.log("GestureDetector ---1");
},
),
),
),
);
分析前先说明dispatchEvent大概流程。 flutter把所有命中测试放到了集合里面, 在分发的时候循环集合调用目标的目标的 handleEvent 这时候判断目标有没有手势识别器(注意入口代码是以带入手势识别器去分析,如果没有手势识别器又是另外一种分发逻辑)有手势识别器把当前识别器添加到路由。完成整个循环后调用路由管理去调用识别器接口(识别器有很多,但是触发的只能一个,所以多个识别器会竞争。路由管理只有两种策略,一种第一个就满足, 一种是只剩最后一个就满足)
GestureBindin void _handlePointerEventImmediately(PointerEvent event) { ...省略 if (hitTestResult != null || event is PointerAddedEvent || event is PointerRemovedEvent) { assert(event.position != null); dispatchEvent(event, hitTestResult); } }
void dispatchEvent(PointerEvent event, HitTestResult? hitTestResult) { ...省略 for (final HitTestEntry entry in hitTestResult.path) { try { //注意这里实际是调用的render 的handleEvent. 后面会调用识别器的handleEvent entry.target.handleEvent(event.transformed(entry.transform), entry); } catch (exception, stack) { ...省略 )); } } }
以上一篇最后一张图开始进入分析text我们没有添加手势识别器 所以往父类在找
GestureDetector
我们监听了点击事件,在build里面发现了, 它自动添加了点击的手势识别器
@override Widget build(BuildContext context) { final Mapgestures = {}; //我们实现了点击事件 if (onTapDown != null || onTapUp != null || onTap != null || ,,,省略 ) { //添加手势点击识别器 gestures[TapGestureRecognizer] = GestureRecognizerFactoryWithHandlers ( () => TapGestureRecognizer(debugOwner: this), (TapGestureRecognizer instance) { instance ..onTapDown = onTapDown ..onTapUp = onTapUp //把我们实现的点击事件赋值给创建的识别器 ..onTap = onTap ...省略 }, ); } ...省略 如果我们实现了其他事件也会添加对应识别器(这里可以看出GestureDetector组件都是在组合各种识别器) return RawGestureDetector( //把识别器集合传入进去 gestures: gestures, behavior: behavior, excludeFromSemantics: excludeFromSemantics, child: child, ); }
RawGestureDetectorState
上一步返回的RawGestureDetector ,看其实现的state build
@override Widget build(BuildContext context) { //又在外面包裹了一层Listener 并且实现了onPointerDown Widget result = Listener( onPointerDown: _handlePointerDown, behavior: widget.behavior ?? _defaultBehavior, child: widget.child, ); if (!widget.excludeFromSemantics) { result = _GestureSemantics( behavior: widget.behavior ?? _defaultBehavior, assignSemantics: _updateSemanticsForRenderObject, child: result, ); } return result; }
这里可以看到 Listener的。触摸事件是调用了识别器。(这里就是开头说明 有识别器和没有识别器的分发会逻辑会不一致。如果不用识别器后面一系列带识别器的分发都不会走了) 这个路由后面在分析现在继续往下走
void _handlePointerDown(PointerDownEvent event) { assert(_recognizers != null); for (final GestureRecognizer recognizer in _recognizers!.values) recognizer.addPointer(event); }
RenderPointerListener
RawGestureDetectorState 里面又包裹了 Listener _GestureSemantics 主要分析Listener 。 Listener里面最终创建RenderPointerListener. 调用的handleEvent
@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); }
最后回调的是RawGestureDetectorState._handlePointerDown void _handlePointerDown(PointerDownEvent event) { assert(_recognizers != null); //中间会有一个数据的转换方法_syncAll,这个可以自己看就不再放出来 for (final GestureRecognizer recognizer in _recognizers!.values) //识别器添加当前事件 recognizer.addPointer(event); }
GestureRecognizer
void addPointer(PointerDownEvent event) { //保存此事件 _pointerToKind[event.pointer] = event.kind; //是否允许跟踪指针默认true(与GestureArenaManager有关) if (isPointerAllowed(event)) { //添加跟踪 addAllowedPointer(event); } else { handleNonAllowedPointer(event); } }
BaseTapGestureRecognizer
我们实现的 TapGestureRecognizer 调用父类的方法
@override void addAllowedPointer(PointerDownEvent event) { assert(event != null); //默认ture if (state == GestureRecognizerState.ready) { ...省略 _down = event; } if (_down != null) { super.addAllowedPointer(event); } }
PrimaryPointerGestureRecognizer
@override void addAllowedPointer(PointerDownEvent event) { //这一步就是添加识别器到路由 super.addAllowedPointer(event); if (state == GestureRecognizerState.ready) { //添加成功后改变状态 _state = GestureRecognizerState.possible; _primaryPointer = event.pointer; _initialPosition = OffsetPair(local: event.localPosition, global: event.position); //默认true。deadline默认100 if (deadline != null) _timer = Timer(deadline!, () => didExceedDeadlineWithEvent(event)); } }
OneSequenceGestureRecognizer
根据上一步调用super.addAllowedPointer(event) 最终到达startTrackingPointer
@protected void startTrackingPointer(int pointer, [Matrix4? transform]) { //添加当前识别器到全局路由, //pointer 就是事件id //handleEvent 就是回调方法 //transform 简单说就是坐标转换 GestureBinding.instance!.pointerRouter.addRoute(pointer, handleEvent, transform); //保存当前事件id _trackedPointers.add(pointer); assert(!_entries.containsValue(pointer)); //保存手势竞争 _entries[pointer] = _addPointerToArena(pointer); }
把当前识别器放入到GestureArenaManager 添加竞争
GestureArenaEntry _addPointerToArena(int pointer) { if (_team != null) return _team!.add(pointer, this); return GestureBinding.instance!.gestureArena.add(pointer, this); }
BaseTapGestureRecognizer
//上一步完成后。继续往下执行 调用didExceedDeadlineWithEvent。 最终调用TapGestureRecognizer.didExceedDeadline. 后者又调用_checkDown
void _checkDown() { //默认flase if (_sentTapDown) { return; } //这个方法进入后会不满足条件而不执行, 所以就不往里走 handleTapDown(down: _down!); //所以第二次 GestureDetector 就不会玩下走 _sentTapDown = true; }
这时候每个都会这样调用 handleEvent 直到调用 hitTestResult 最后一个 才会有变化
GestureBinding
//hitTestResult 循环到最后一个就会调用 GestureBinding .handleEvent
@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) { //再次接受到up指令直接让第一个识别器胜利 回调 gestureArena.sweep(event.pointer); } else if (event is PointerSignalEvent) { pointerSignalResolver.resolve(event); } }
PointerRouter
路由开始处理已有的识别器
void route(PointerEvent event) { ..省略 调用 _dispatchEventToRoutes(event, _globalRoutes, copiedGlobalRoutes); }
void _dispatchEventToRoutes( PointerEvent event, MapreferenceRoutes, Map copiedRoutes, ) { copiedRoutes.forEach((PointerRoute route, Matrix4? transform) { //判断之前的路由是否还存在(可能会在循环中删掉路由,有些元素 竞技成功 其他的同类路由监听的就会删掉) if (referenceRoutes.containsKey(route)) { //循环调用 _dispatch(event, route, transform); } }); }
void _dispatch(PointerEvent event, PointerRoute route, Matrix4? transform) { try { event = event.transformed(transform); //回调每个handleEvent route(event); } catch (exception, stack) { ....省略 } }
PrimaryPointerGestureRecognizer
其他省略。直接跳转到 TapGestureRecognizer.handleEvent 自己没有复写 最后调用
PrimaryPointerGestureRecognizer.handleEvent
@override void handleEvent(PointerEvent event) { assert(state != GestureRecognizerState.ready); //这时候满足条件状态变了 if (state == GestureRecognizerState.possible && event.pointer == primaryPointer) { ...省略 if (event is PointerMoveEvent && (isPreAcceptSlopPastTolerance || isPostAcceptSlopPastTolerance)) { resolve(GestureDisposition.rejected); stopTrackingPointer(primaryPointer!); } else { //调用 handlePrimaryPointer(event); } } stopTrackingIfPointerNoLongerDown(event); }
@override void handlePrimaryPointer(PointerEvent event) { //因为传过来的是触摸事件所以不满足。循环到结束 if (event is PointerUpEvent) { //直到传过来up _up = event; _checkUp(); } ...省略 } 入口代码有两个GestureDetector 所以会触发两次 //两次都会不满足条件而不执行 void _checkUp() { //直到执行gestureArena.sweep(event.pointer) 调用第一个组件的acceptGesture 其他的调用rejectGesture if (!_wonArenaForPrimaryPointer || _up == null) { return; } assert(_up!.pointer == _down!.pointer); //触发GestureDetector 的回调 (完结。这是带有识别器的分发逻辑) handleTapUp(down: _down!, up: _up!); _reset(); }
@override void acceptGesture(int pointer) { super.acceptGesture(pointer); if (pointer == primaryPointer) { _checkDown(); //这时候只置为ture _wonArenaForPrimaryPointer = true; //再次调用 看上一段 _checkUp(); } }