streamline the hit test logic a bit ( maybe ) + add option to register adhoc pointer event listeners

This commit is contained in:
2025-08-16 20:37:06 +00:00
parent 066ab24ca0
commit 6ba97315a7
3 changed files with 56 additions and 16 deletions
+10 -10
View File
@@ -102,26 +102,26 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker name: leak_tracker
sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" sha256: "8dcda04c3fc16c14f48a7bb586d4be1f0d1572731b6d81d51772ef47c02081e0"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "10.0.9" version: "11.0.1"
leak_tracker_flutter_testing: leak_tracker_flutter_testing:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker_flutter_testing name: leak_tracker_flutter_testing
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.9" version: "3.0.10"
leak_tracker_testing: leak_tracker_testing:
dependency: transitive dependency: transitive
description: description:
name: leak_tracker_testing name: leak_tracker_testing
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.0.1" version: "3.0.2"
lints: lints:
dependency: transitive dependency: transitive
description: description:
@@ -219,10 +219,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: test_api name: test_api
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd sha256: "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00"
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "0.7.4" version: "0.7.6"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
@@ -243,10 +243,10 @@ packages:
dependency: transitive dependency: transitive
description: description:
name: vector_math name: vector_math
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.1.4" version: "2.2.0"
vm_service: vm_service:
dependency: transitive dependency: transitive
description: description:
+11
View File
@@ -1,6 +1,7 @@
import 'dart:collection'; import 'dart:collection';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:infinite_lazy_grid/core/background.dart'; import 'package:infinite_lazy_grid/core/background.dart';
import '../../utils/measure_size.dart'; import '../../utils/measure_size.dart';
import '../spatial_hashing.dart'; import '../spatial_hashing.dart';
@@ -41,6 +42,11 @@ class LazyCanvasController with ChangeNotifier {
OnWidgetEnteredRender? onWidgetEnteredRender; OnWidgetEnteredRender? onWidgetEnteredRender;
OnWidgetExitedRender? onWidgetExitedRender; OnWidgetExitedRender? onWidgetExitedRender;
Set<CanvasChildId> _renderedWidgets = {}; // to track which widgets are currently rendered Set<CanvasChildId> _renderedWidgets = {}; // to track which widgets are currently rendered
PointerDownEventListener? rawPointerDownListener;
PointerMoveEventListener? rawPointerMoveListener;
PointerUpEventListener? rawPointerUpListener;
PointerCancelEventListener? rawPointerCancelListener;
PointerSignalEventListener? rawPointerSignalListener;
bool debug; bool debug;
final Duration defaultAnimationDuration; final Duration defaultAnimationDuration;
@@ -54,6 +60,11 @@ class LazyCanvasController with ChangeNotifier {
this.useIdsFromArgs = false, this.useIdsFromArgs = false,
this.onWidgetEnteredRender, this.onWidgetEnteredRender,
this.onWidgetExitedRender, this.onWidgetExitedRender,
this.rawPointerSignalListener,
this.rawPointerDownListener,
this.rawPointerMoveListener,
this.rawPointerUpListener,
this.rawPointerCancelListener,
}) : _hashCellSize = hashCellSize, }) : _hashCellSize = hashCellSize,
_buildCacheExtent = buildCacheExtent != null ? buildCacheExtent + _kBuildCacheBuffer : null _buildCacheExtent = buildCacheExtent != null ? buildCacheExtent + _kBuildCacheBuffer : null
// only top left is considered so if a widget has long width, it'll not be rendered // only top left is considered so if a widget has long width, it'll not be rendered
+35 -6
View File
@@ -56,7 +56,13 @@ class _LazyCanvasState extends State<LazyCanvas> with TickerProviderStateMixin<L
} }
} }
} }
// handle any other registered signal events
widget.controller.rawPointerSignalListener?.call(event);
}, },
onPointerDown: widget.controller.rawPointerDownListener,
onPointerMove: widget.controller.rawPointerMoveListener,
onPointerUp: widget.controller.rawPointerUpListener,
onPointerCancel: widget.controller.rawPointerCancelListener,
child: GestureDetector( child: GestureDetector(
behavior: HitTestBehavior.translucent, behavior: HitTestBehavior.translucent,
onScaleUpdate: widget.controller.onScaleUpdate, onScaleUpdate: widget.controller.onScaleUpdate,
@@ -298,14 +304,37 @@ class _CanvasRenderBox extends RenderBox
bool hitTestChildren(BoxHitTestResult result, {required Offset position}) { bool hitTestChildren(BoxHitTestResult result, {required Offset position}) {
RenderBox? child = lastChild; RenderBox? child = lastChild;
while (child != null) { while (child != null) {
// need to get a coordinate in child space final _CanvasWidgetParentData childParentData = child.parentData! as _CanvasWidgetParentData;
final childParentData = child.parentData as _CanvasWidgetParentData;
final Offset childSpacePosition = bool isHit;
(position - childParentData.offset /* <- distance in screen space */ ) / childParentData.scale; if (childParentData.scale == 1.0) {
// divide by scale so if screen space is 2x, it's only x in child space // Fast path: only translated, no scale
if (child.hitTest(result, position: childSpacePosition)) { isHit = result.addWithPaintOffset(
offset: childParentData.offset,
position: position,
hitTest: (BoxHitTestResult result, Offset transformed) {
return child!.hitTest(result, position: transformed);
},
);
} else {
// same paint transform for hit testing when scaled
final Matrix4 transform = Matrix4.identity()
..translate(childParentData.offset.dx, childParentData.offset.dy)
..scale(childParentData.scale, childParentData.scale);
isHit = result.addWithPaintTransform(
transform: transform,
position: position,
hitTest: (BoxHitTestResult result, Offset transformed) {
return child!.hitTest(result, position: transformed);
},
);
}
if (isHit) {
return true; return true;
} }
child = childParentData.previousSibling; child = childParentData.previousSibling;
} }
return false; return false;