classifyDesktopHit function
通过 hit test 分类 globalPosition 的交互属性。
检测顺序:
- RenderEditable → 输入框
- RenderMyDoubleClickConsumeZone → 显式标记
- RenderSemanticsGestureHandler.onTap 非空 → InkWell / 带 onTap 或 onTapDown 的 GestureDetector 等
Scrollable 等只有 scroll/drag 语义的 handler(onTap == null)不算交互,
这样列表空白处仍能双击最大化。
Flutter 只要存在 TapGestureRecognizer(包括仅 onSecondaryTapDown)
就会填上非空 onTap。整页右键请用 showRightMenu(内部是 Listener),
不要自行用 GestureDetector(onSecondaryTapDown) 包一整页。整页
GestureDetector(onTap: unfocus) 同样会关掉空白处最大化。
Implementation
MyDesktopHitKind classifyDesktopHit(Offset globalPosition) {
final viewId =
WidgetsBinding.instance.platformDispatcher.implicitView?.viewId;
if (viewId == null) return MyDesktopHitKind.background;
final result = HitTestResult();
WidgetsBinding.instance.hitTestInView(result, globalPosition, viewId);
var hasEditable = false;
var hasConsumeZone = false;
var hasTapInteractive = false;
for (final entry in result.path) {
final target = entry.target;
if (target is RenderEditable) hasEditable = true;
if (target is RenderMyDoubleClickConsumeZone) hasConsumeZone = true;
if (target is RenderSemanticsGestureHandler && target.onTap != null) {
hasTapInteractive = true;
}
}
if (hasEditable) return MyDesktopHitKind.editable;
if (hasConsumeZone || hasTapInteractive) {
return MyDesktopHitKind.interactive;
}
return MyDesktopHitKind.background;
}