-
Notifications
You must be signed in to change notification settings - Fork 29.7k
[ios][pv]accept/reject gesture based on hit test #177859
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
5bfaaac to
10561f9
Compare
10561f9 to
1e2c256
Compare
| } | ||
|
|
||
| @pragma('vm:entry-point') | ||
| bool _platformViewShouldAcceptGesture(int viewId, double x, double y) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm debating myself about calling it _platformViewShouldAcceptGesture vs _iOSPlatformViewShouldAcceptGesture (here and rest of the PR). I'm open to input.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since its ios specific i vote the second one
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code after platformViewiOS should be platform neutral, in case other platform also have use case for this method. If you want to specify the use case in iOS, you can put it in the api doc that currently only iOS uses this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good point. Though I couldn't find an existing convention with a platform prefix, so I am not sure... (both about this line, as well as all boilerplates in the engine)
@chunhtai do you have any thoughts on it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this name is fine, since platformView only has one meaning in framework side, and this makes sense
|
I'm still trying something out, but it's ready for review. |
|
@yjbanov just FYI since you are working on something related on the web. |
| return NO; | ||
| } | ||
|
|
||
| - (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the _flutterViewController need to be reset like it does in touchesBegan?
flutter/engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm
Lines 734 to 737 in aed2e42
| // At the start of each gesture sequence, we reset the `_flutterViewController`, | |
| // so that all the touch events in the same sequence are forwarded to the same | |
| // `_flutterViewController`. | |
| _flutterViewController = _platformViewsController.flutterViewController; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no need - hitTest is called before touchBegan starts, so we still have touchBegan covering this reset logic.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apparently i was wrong - we have to set flutterViewController in hitTest, because the flutterViewController may not be set when creating the platform view (race condition). The comment here is probably incorrect and very misleading - we should just set it once so that it's not nil (rather than set it on every touch began).
Credit: #175099 (comment) by @holzgeist
engine/src/flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm
Outdated
Show resolved
Hide resolved
| tonic::DartInvoke(dispatch_pointer_data_packet_.Get(), {data_handle})); | ||
| } | ||
|
|
||
| bool PlatformConfiguration::EmbeddedViewShouldAcceptGesture( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We need to unify the naming, Replace EmbeddedView with PlatformView?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
here and everywhere, we should not change the naming convention in the middle of call chain
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See discussion here: https://github.com/flutter/flutter/pull/177859/files#r2482734556
"platform view" means the flutter view in engine.
If we replace it with "PlatformView", we will end up with an API in platform view's delegate:
OnPlatformViewPlatformViewShouldAcceptGesture
Where the first "PlatformView" refers to the flutter view, and the second "PlatformView" refers to the embedded view. This will be far more confusing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
embedded view sounds like an add-to-app. How about embeddedNativeView?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SG
| } | ||
|
|
||
| @pragma('vm:entry-point') | ||
| bool _platformViewShouldAcceptGesture(int viewId, double x, double y) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this name is fine, since platformView only has one meaning in framework side, and this makes sense
| @@ -14,6 +14,7 @@ import 'dart:collection'; | |||
| import 'dart:ui' as ui show PointerDataPacket; | |||
|
|
|||
| import 'package:flutter/foundation.dart'; | |||
| import 'package:flutter/rendering.dart'; | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
gesture layer can't import rendering. this is layer violation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I may need some help understanding this and how to resolve it. Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See this graph libraries can't import other libraries that stack on top, otherwise it will be a circular dependency.
One way to resolve this is to have a abstract class in this layer
// in gesture layer
abstract NativeHitTarget {}// in Render layer
class RenderUIKitView extends NativeHitTarget{
}and then in here you can check
target is NativeHitTargetThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense! Thanks for the diagram!
| return false; | ||
| } | ||
| final HitTestTarget firstHit = result.path.first.target; | ||
| return firstHit is RenderUiKitView; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we may need a more general way of doing this instead of RenderObject type check.
Consider create an abstract interface in this layer to be extends in Rendering layer.
also what if there are multiple PlatformView?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider create an abstract interface in this layer to be extends in Rendering layer.
Could you elaborate more? thanks
also what if there are multiple PlatformView?
We should be fine - the request was initiated from the platform view on top.
|
Did some research on iPad trackpad: For trackpad touches, it's still a |
| // Block gesture if the framework instructed so (after performing its own hitTest). | ||
| if (![self.flutterViewController | ||
| platformViewShouldAcceptGestureAtTouchBeganLocation:pointInFlutterView]) { | ||
| return self; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand this correctly, if the point is within the FlutterView, the framework will return true. If it returns true, it goes on to super hitTest, which uses the frontmost view that contains the point. If it returns false, it uses the platform view.
Couple questions I'm a little confused on:
- Why do we need to ask the framework at all?
- What happens if there are multiple layered platform views?
- What happens if the FlutterView is above/below the platform view?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand this correctly, if the point is within the FlutterView, the framework will return true.
No, the query to the framework is "Is the top most hit target a platform view at given point?".
Side note: "top most hit target" != "point inside platform view" (see the drop down menu example below)
... which uses the frontmost view that contains the point.
Almost but not always - it also depends on the front-most view (which is the platform view). If the platform view itself overwrites hitTest, and say, redirect to another arbitrary target, it will be respected too.
If it returns false, it uses the platform view.
The opposite - if it returns false, that means platform view shouldn't receive the touch. HitTest is a pre-order tree traversal (visiting parent before children). We return self here to tell UIKit, "hey I (the touch interceptor view) will take care of the touch, so don't visit my children (the platform view)"
Why do we need to ask the framework at all?
My MVP version actually skips the framework query and relies on overlay layer. However, there are cases where overlay layer doesn't work. For example, when drop down menu is shown, there will be an invisible "barrier" covering the whole screen, which won't create an overlay since it's invisible.
What happens if there are multiple layered platform views?
It's fine - UIKit will make sure the correct touch interceptor view receives the touch and sends requests to framework.
What happens if the FlutterView is above/below the platform view?
I assume FlutterView you mean a flutter widget covering the platform view?
If we have flutter widget above the platform view - framework would return false from hitTest, so the touch interceptor would block the gesture (by returning self in hitTest). If below, then the opposite.
| // The embedded platform view (e.g. UIView on iOS) is called "platform view" | ||
| // on framework side, but "embedded view" on engine side. On the other hand, | ||
| // "platform view" refers to the whole flutter view on engine side. | ||
| embedded_view_should_accept_gesture_.Set( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit: Rename to "embedded_native_view..." to keep inline
| embedded_view_should_accept_gesture_.Set( | |
| embedded_native_view_should_accept_gesture_.Set( |
| tonic::DartPersistentValue update_accessibility_features_; | ||
| tonic::DartPersistentValue dispatch_platform_message_; | ||
| tonic::DartPersistentValue dispatch_pointer_data_packet_; | ||
| tonic::DartPersistentValue embedded_view_should_accept_gesture_; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| tonic::DartPersistentValue embedded_view_should_accept_gesture_; | |
| tonic::DartPersistentValue embedded_native_view_should_accept_gesture_; |
| tonic::DartState::Current(), | ||
| Dart_GetField(library, tonic::ToDart("_dispatchPointerDataPacket"))); | ||
| // The embedded platform view (e.g. UIView on iOS) is called "platform view" | ||
| // on framework side, but "embedded view" on engine side. On the other hand, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // on framework side, but "embedded view" on engine side. On the other hand, | |
| // on framework side, but "embedded native view" on engine side. On the other hand, |
jmagman
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd prefer to create a new policy
I think this needs a serious design doc before it's landed, particularly around how devs are supposed to know how to use this policy, the migration and documentation story.
Obviously this would be better if this works for everyone automatically without plugins chasing policies.
Additionally, this will allow other platform teams to converge on similar solutions.
|
I tried using this PR to compile the local engine, but I couldn’t build the iOS project — it shows an error. The setter 'onPlatformViewShouldAcceptGesture' isn't defined for the type 'PlatformDispatcher'. |
|
(triage) @hellohuanlin is this pr ready for another look? |
Same for me. |
This PR updates both the engine and the framework. This error message sounds like you used the new engine but not the new framework. You may have to do a |
It is working for me now thanks @hellohuanlin |
|
@hellohuanlin any update for this? |
| typedef SemanticsActionEventCallback = void Function(SemanticsActionEvent action); | ||
|
|
||
| /// Signature for [PlatformDispatcher.onPlatformViewShouldAcceptGesture]. | ||
| typedef PlatformViewShouldAcceptGestureCallback = bool Function(int viewId, double x, double y); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe with the current API adding a new parameter to this callback would be a breaking change.
I'd consider moving all these arguments to a FooEvent type to improve the API's forward compatibility (you can add a new property Adding a new property to FooEvent wouldn't be a breaking
(You might also want to consider returning an enum instead of a boolean, but I feel less strongly about this)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd consider:
| typedef PlatformViewShouldAcceptGestureCallback = bool Function(int viewId, double x, double y); | |
| class HitTestRequest { | |
| const HitTestRequest({required this.view, required this.offset}); | |
| final FlutterView view; | |
| final Offset offset; | |
| } | |
| class HitTestResponse { | |
| const HitTestResponse({required this.firstHitIsPlatformView}); | |
| final bool firstHitIsPlatformView; | |
| } | |
| typedef HitTestCallback = HitTestResponse Function(HitTestRequest request); |
This makes the API a bit more generic, less tied to iOS's specific needs, and allows us to add more features in the future.
| typedef SemanticsActionEventCallback = void Function(SemanticsActionEvent action); | ||
|
|
||
| /// Signature for [PlatformDispatcher.onPlatformViewShouldAcceptGesture]. | ||
| typedef PlatformViewShouldAcceptGestureCallback = bool Function(int viewId, double x, double y); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of providing the callback a int viewId, I'd consider providing a FlutterView view. The callback can easily get the ID from a view, but not vice versa
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd also consider accepting an Offset offset instead of double x, double y - that's more ergonomic for Flutter. See above: #177859 (comment)
|
Hi @hellohuanlin should we close this one since there is another pr #179659? |
|
Closing in favor of #179659 |
#179659) This is a follow up PR to [this original PR](#177859). The difference is the API - the original PR chooses Option 1 [in the design doc](https://docs.google.com/document/d/1ag4drAdJsR7y-rQZkqJWc6tOQ4qCbflQSGyoxsSC6MM/edit?tab=t.0), while this PR chooses Option 3. ## Usage To directly use flutter API, just pass in the policy when creating UiKitView widget. ``` UiKitView( ... gestureBlockingPolicy: UiKitViewGestureBlockingPolicy) ... ) ``` For plugins, we need to update plugins to use this new API. ``` WebView( ... gestureBlockingPolicy: UiKitViewGestureBlockingPolicy ) { return UiKitView( .. gestureBlockingPolicy: gestureBlockingPolicy ) } ``` For more information, refer to [the old PR](#177859). *List which issues are fixed by this PR. You must list at least one issue. An issue is not required if the PR fixes something trivial like a typo.* #175099 #165787 *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
flutter#179659) This is a follow up PR to [this original PR](flutter#177859). The difference is the API - the original PR chooses Option 1 [in the design doc](https://docs.google.com/document/d/1ag4drAdJsR7y-rQZkqJWc6tOQ4qCbflQSGyoxsSC6MM/edit?tab=t.0), while this PR chooses Option 3. ## Usage To directly use flutter API, just pass in the policy when creating UiKitView widget. ``` UiKitView( ... gestureBlockingPolicy: UiKitViewGestureBlockingPolicy) ... ) ``` For plugins, we need to update plugins to use this new API. ``` WebView( ... gestureBlockingPolicy: UiKitViewGestureBlockingPolicy ) { return UiKitView( .. gestureBlockingPolicy: gestureBlockingPolicy ) } ``` For more information, refer to [the old PR](flutter#177859). *List which issues are fixed by this PR. You must list at least one issue. An issue is not required if the PR fixes something trivial like a typo.* flutter#175099 flutter#165787 *If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].* ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [x] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [x] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] I followed the [breaking change policy] and added [Data Driven Fixes] where supported. - [ ] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. **Note**: The Flutter team is currently trialing the use of [Gemini Code Assist for GitHub](https://developers.google.com/gemini-code-assist/docs/review-github-code). Comments from the `gemini-code-assist` bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview [Tree Hygiene]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md [test-exempt]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests [Flutter Style Guide]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md [Features we expect every widget to implement]: https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md [Data Driven Fixes]: https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md
Use hit test instead of delaying recognizer to block platform view gestures. This fixes web view and admob not tappable issue linked below.
Problem with delaying recognizer
There was an Apple bug that causes our delaying recognizer to conflict with web view's internal gesture recognizers. You can read more detailed research on this bug here: flutter/engine#57032. Also, we repro'ed it in native app and filed a radar with Apple.
hit test & FFI to the rescue
We perform a simple hitTest to decide whether to block the gesture or not. We had an MVP version (closed) that uses the platform view's "overlay layer". However, there are 2 issues with this MVP version:
(1) There can be use cases where even if we touch outside of "overlap" (or no overlap at all), we still want to block gestures
(2) overlaps are merged into a single UIView in our current implementation. This means if you have multiple overlaps, the blocking region would be a bounding box that contains all overlaps;
There is also a previous attempt to use hit test to block the gesture, where the embedder blocks the main thread, wait for the asynchronous response from framework, and decide to block or not. Given that UI & platform threads are merged, this will 100% cause deadlock (main thread waiting for main thread).
Luckily, with FFI, we are able to query the framework and get the result synchronously, which solves the deadlock problem above.
Usage
To reduce risk of (serious) regression, I'd prefer to create a new policy
FlutterPlatformViewGestureRecognizersBlockingPolicyHitTest(rather than reusing existing policy). Plugin owners would need to either use this policy, or create an API to allow change of polices. Developers can also overwrite their plugin locally, or use method swizzling.My next task would be to update 1p web_view & admob plugins, but I probably won't do it for 3p plugins.
Pointer interceptor deprecation
We had a pointer interceptor plugin created for a similar bug. Pointer interceptor doesn't work in #175099 (comment) (webview) and #165787 (admob), because they don't have flutter widget on top of platform view. Another problem with pointer interceptor is that it requires developers to wrap their widgets.
I can confirm that this hit test approach also fixes the original issue fixed by pointer interceptor. So with this, we will be able to deprecate pointer_interceptor plugin (which will be my next TODO item).
Misc
This is not related to #176476, which is likely a separate Apple bug that we should file a radar
List which issues are fixed by this PR. You must list at least one issue. An issue is not required if the PR fixes something trivial like a typo.
Fixes #175099
Fixes #165787
If you had to change anything in the flutter/tests repo, include a link to the migration guide as per the breaking change policy.
Pre-launch Checklist
///).If you need help, consider asking for advice on the #hackers-new channel on Discord.
Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the
gemini-code-assistbot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.