还是以下面代码为入口去分析
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 Map<Type, GestureRecognizerFactory> gestures = <Type, GestureRecognizerFactory>{};
//我们实现了点击事件
if (onTapDown != null ||
onTapUp != null ||
onTap != null ||
,,,省略
) {
//添加手势点击识别器
gestures[TapGestureRecognizer] = GestureRecognizerFactoryWithHandlers<TapGestureRecognizer>(
() => 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,
Map<PointerRoute, Matrix4?> referenceRoutes,
Map<PointerRoute, Matrix4?> 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();
}
}
本文详细解析了Flutter中GestureDetector的事件处理过程,包括dispatchEvent的逻辑,如何添加和管理手势识别器,以及路由机制在不同情境下的行为。重点讨论了带手势识别器和不带的分发逻辑差异及PrimaryPointerGestureRecognizer的处理流程。
1051

被折叠的 条评论
为什么被折叠?



