From dda5805935568d42b71a1a1faf7fbdf078d72633 Mon Sep 17 00:00:00 2001 From: Till Friebe Date: Fri, 19 Mar 2021 17:15:22 +0100 Subject: [PATCH] Add hitTesting to allow changing click behavior in embeds The code change allows to override the default behaviour of clicking on images and thus solves #90. Now the only thing left to do is to use a `RawGestureDetector` in the `EmbedBuilder` to deactivate the "old" behaviour (by entering the GestureArena and win). The `embedBuilder` could look like this: ```dart Widget embedBuilder(BuildContext context, Embed node, bool readOnly) { return FutureBuilder( future: File('image_path.png'), builder: (context, snapshot) { final gestures = { ReadDependentGestureRecognizer: GestureRecognizerFactoryWithHandlers< ReadDependentGestureRecognizer>( () => ReadDependentGestureRecognizer(readOnly: readOnly), (instance) => instance ..onTapUp = ((_) => print('Test')) ) }; return RawGestureDetector( gestures: gestures, child: Image.file(snapshot.data), ); } ); } class ReadDependentGestureRecognizer extends TapGestureRecognizer { ReadDependentGestureRecognizer({@required this.readOnly}); final bool readOnly; @override bool isPointerAllowed(PointerDownEvent event) { if (!readOnly) { return false; } return super.isPointerAllowed(event); } } ``` **Explanation of the code:** When a `PointerDownEvent` is received by the `GestureBinding` a hit test is performed to determine which `HitTestTarget` nodes are affected. For this the (I think) element tree is traversed downwards to find out which elements has been hit. To find out which elements were hit, the method `hitTestSelf` and `hitTestChildren` are used. Since the `hitTestChildren` method of `TextLine` has not been implemented yet, `false` was always returned, which is why the hit test never arrived at the `embedBuilder`. With the code change, the hit is passed on and can be processed correctly in the embed. Additionally I removed the class `_TransparentTapGestureRecognizer`, because this class always accepted the gesture, even if the recognizer lost in the arena. --- lib/widgets/text_line.dart | 5 +++++ lib/widgets/text_selection.dart | 23 ++++------------------- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/lib/widgets/text_line.dart b/lib/widgets/text_line.dart index ffe7ee93..a9260e8f 100644 --- a/lib/widgets/text_line.dart +++ b/lib/widgets/text_line.dart @@ -785,6 +785,11 @@ class RenderEditableTextLine extends RenderEditableBox { ); _cursorPainter.paint(context.canvas, effectiveOffset, position); } + + @override + bool hitTestChildren(BoxHitTestResult result, {Offset position}) { + return this._children.first.hitTest(result, position: position); + } } class _TextLineElement extends RenderObjectElement { diff --git a/lib/widgets/text_selection.dart b/lib/widgets/text_selection.dart index e74318ac..0790cbd0 100644 --- a/lib/widgets/text_selection.dart +++ b/lib/widgets/text_selection.dart @@ -670,10 +670,10 @@ class _EditorTextSelectionGestureDetectorState final Map gestures = {}; - gestures[_TransparentTapGestureRecognizer] = - GestureRecognizerFactoryWithHandlers<_TransparentTapGestureRecognizer>( - () => _TransparentTapGestureRecognizer(debugOwner: this), - (_TransparentTapGestureRecognizer instance) { + gestures[TapGestureRecognizer] = + GestureRecognizerFactoryWithHandlers( + () => TapGestureRecognizer(debugOwner: this), + (TapGestureRecognizer instance) { instance ..onTapDown = _handleTapDown ..onTapUp = _handleTapUp @@ -735,18 +735,3 @@ class _EditorTextSelectionGestureDetectorState ); } } - -class _TransparentTapGestureRecognizer extends TapGestureRecognizer { - _TransparentTapGestureRecognizer({ - Object debugOwner, - }) : super(debugOwner: debugOwner); - - @override - void rejectGesture(int pointer) { - if (state == GestureRecognizerState.ready) { - acceptGesture(pointer); - } else { - super.rejectGesture(pointer); - } - } -}