Skip to content

Commit

Permalink
[web] Set touch-action:none in embedded views. (flutter#53945)
Browse files Browse the repository at this point in the history
This PR adds `touch-action:none` to `flutter-view` elements, so the browser lets the flutter engine fully handle all touch gestures.

This fix is more delicate than the first approach, which broke some merged taps when accessibility/semantics are enabled. 

## Issues

* Found while testing: flutter/flutter#130950
* "More correct" fix for: flutter#53647

## Demos

* Flutter scroll: https://dit-multiview-scroll.web.app
* Semantics: https://dit-tests.web.app
* Scrollable platform views: https://dit-multiview-tests.web.app

[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
  • Loading branch information
ditman committed Jul 19, 2024
1 parent 8274f54 commit c509b0c
Show file tree
Hide file tree
Showing 4 changed files with 9 additions and 18 deletions.
14 changes: 0 additions & 14 deletions lib/web_ui/lib/src/engine/pointer_binding.dart
Original file line number Diff line number Diff line change
Expand Up @@ -968,20 +968,6 @@ class _PointerAdapter extends _BaseAdapter with _WheelEventListenerMixin {

@override
void setup() {
// Prevents the browser auto-canceling pointer events.
// Register into `_listener` directly so the event isn't forwarded to semantics.
_listeners.add(Listener.register(
event: 'touchstart',
target: _viewTarget,
handler: (DomEvent event) {
// This is one of the ways I've seen this done. PixiJS does a similar thing.
// ThreeJS seems to subscribe move/leave in the pointerdown handler instead?
if (event.cancelable) {
event.preventDefault();
}
},
));

_addPointerEventListener(_viewTarget, 'pointerdown', (DomPointerEvent event) {
final int device = _getPointerId(event);
final List<ui.PointerData> pointerData = <ui.PointerData>[];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,10 @@ class CustomElementEmbeddingStrategy implements EmbeddingStrategy {
..style.height = '100%'
..style.display = 'block'
..style.overflow = 'hidden'
..style.position = 'relative';
..style.position = 'relative'
// This is needed so the browser lets flutter handle all pointer events
// it receives, without canceling them.
..style.touchAction = 'none';

hostElement.appendChild(rootElement);

Expand Down
6 changes: 3 additions & 3 deletions lib/web_ui/test/engine/pointer_binding_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -305,15 +305,15 @@ void testMain() {
},
);

test('prevents default on touchstart events', () async {
test('allows default on touchstart events', () async {
final event = createDomEvent('Event', 'touchstart');

rootElement.dispatchEvent(event);

expect(
event.defaultPrevented,
isTrue,
reason: 'touchstart events should be prevented so pointer events are not cancelled later.',
isFalse,
reason: 'touchstart events should NOT be prevented. That breaks semantic taps!',
);
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,8 @@ void doTests() {
reason: 'Should take 100% of the available height');
expect(styleAfter.overflow, 'hidden',
reason: 'Should hide the occasional oversized canvas elements.');
expect(styleAfter.touchAction, 'none',
reason: 'Should disable browser handling of touch events.');
});
});
}

0 comments on commit c509b0c

Please sign in to comment.