未验证 提交 245317a6 编写于 作者: A Amir Hardon 提交者: GitHub

Reland "Only reject gestures to embedded UIViews when the framework sa… (#7315)

This re-lands commit cc9c6702, with a few fixes:

  - Keep the DelayingGestureRecognizer a discrete gesture recognizer, when it was set to a began state embedded WkWebViews wasn't receiving touch events.
  - Fix a bug of not retaining the forwardRecognizer pointer when assigning it to a scoped_nsobject.
上级 be69b07c
......@@ -29,6 +29,8 @@ void FlutterPlatformViewsController::OnMethodCall(FlutterMethodCall* call, Flutt
OnDispose(call, result);
} else if ([[call method] isEqualToString:@"acceptGesture"]) {
OnAcceptGesture(call, result);
} else if ([[call method] isEqualToString:@"rejectGesture"]) {
OnRejectGesture(call, result);
} else {
result(FlutterMethodNotImplemented);
}
......@@ -125,6 +127,24 @@ void FlutterPlatformViewsController::OnAcceptGesture(FlutterMethodCall* call,
result(nil);
}
void FlutterPlatformViewsController::OnRejectGesture(FlutterMethodCall* call,
FlutterResult& result) {
NSDictionary<NSString*, id>* args = [call arguments];
int64_t viewId = [args[@"id"] longLongValue];
if (views_.count(viewId) == 0) {
result([FlutterError errorWithCode:@"unknown_view"
message:@"trying to set gesture state for an unknown view"
details:[NSString stringWithFormat:@"view id: '%lld'", viewId]]);
return;
}
FlutterTouchInterceptingView* view = touch_interceptors_[viewId].get();
[view blockGesture];
result(nil);
}
void FlutterPlatformViewsController::RegisterViewFactory(
NSObject<FlutterPlatformViewFactory>* factory,
NSString* factoryId) {
......@@ -269,6 +289,9 @@ void FlutterPlatformViewsController::EnsureGLOverlayInitialized(
// invoking an acceptGesture method on the platform_views channel). And this is how we allow the
// Flutter framework to delay or prevent the embedded view from getting a touch sequence.
@interface DelayingGestureRecognizer : UIGestureRecognizer <UIGestureRecognizerDelegate>
- (instancetype)initWithTarget:(id)target
action:(SEL)action
forwardingRecognizer:(UIGestureRecognizer*)forwardingRecognizer;
@end
// While the DelayingGestureRecognizer is preventing touches from hitting the responder chain
......@@ -301,7 +324,10 @@ void FlutterPlatformViewsController::EnsureGLOverlayInitialized(
[[[ForwardingGestureRecognizer alloc] initWithTarget:self
flutterView:flutterView] autorelease];
_delayingRecognizer.reset([[DelayingGestureRecognizer alloc] initWithTarget:self action:nil]);
_delayingRecognizer.reset([[DelayingGestureRecognizer alloc]
initWithTarget:self
action:nil
forwardingRecognizer:forwardingRecognizer]);
[self addGestureRecognizer:_delayingRecognizer.get()];
[self addGestureRecognizer:forwardingRecognizer];
......@@ -312,21 +338,34 @@ void FlutterPlatformViewsController::EnsureGLOverlayInitialized(
- (void)releaseGesture {
_delayingRecognizer.get().state = UIGestureRecognizerStateFailed;
}
- (void)blockGesture {
_delayingRecognizer.get().state = UIGestureRecognizerStateEnded;
}
@end
@implementation DelayingGestureRecognizer
- (instancetype)initWithTarget:(id)target action:(SEL)action {
@implementation DelayingGestureRecognizer {
fml::scoped_nsobject<UIGestureRecognizer> _forwardingRecognizer;
}
- (instancetype)initWithTarget:(id)target
action:(SEL)action
forwardingRecognizer:(UIGestureRecognizer*)forwardingRecognizer {
self = [super initWithTarget:target action:action];
if (self) {
self.delaysTouchesBegan = YES;
self.delegate = self;
_forwardingRecognizer.reset([forwardingRecognizer retain]);
}
return self;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer {
return otherGestureRecognizer != self;
// The forwarding gesture recognizer should always get all touch events, so it should not be
// required to fail by any other gesture recognizer.
return otherGestureRecognizer != _forwardingRecognizer.get() && otherGestureRecognizer != self;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
......@@ -334,21 +373,8 @@ void FlutterPlatformViewsController::EnsureGLOverlayInitialized(
return otherGestureRecognizer == self;
}
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
// The gesture has ended, and the delaying gesture recognizer was not failed, we recognize
// the gesture to prevent the touches from being dispatched to the embedded view.
//
// This doesn't work well with gestures that are recognized by the Flutter framework after
// all pointers are up.
//
// TODO(amirh): explore if we can instead set this to recognized when the next touch sequence
// begins, or we can use a framework signal for restarting the recognizers (e.g when the
// gesture arena is resolved).
self.state = UIGestureRecognizerStateRecognized;
}
- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event {
self.state = UIGestureRecognizerStateRecognized;
self.state = UIGestureRecognizerStateFailed;
}
@end
......@@ -380,12 +406,12 @@ void FlutterPlatformViewsController::EnsureGLOverlayInitialized(
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
[_flutterView touchesEnded:touches withEvent:event];
self.state = UIGestureRecognizerStateRecognized;
self.state = UIGestureRecognizerStateEnded;
}
- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event {
[_flutterView touchesCancelled:touches withEvent:event];
self.state = UIGestureRecognizerStateRecognized;
self.state = UIGestureRecognizerStateFailed;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
......
......@@ -22,6 +22,9 @@
// Stop delaying any active touch sequence (and let it arrive the embedded view).
- (void)releaseGesture;
// Prevent the touch sequence from ever arriving to the embedded view.
- (void)blockGesture;
@end
namespace shell {
......@@ -89,6 +92,7 @@ class FlutterPlatformViewsController {
void OnCreate(FlutterMethodCall* call, FlutterResult& result);
void OnDispose(FlutterMethodCall* call, FlutterResult& result);
void OnAcceptGesture(FlutterMethodCall* call, FlutterResult& result);
void OnRejectGesture(FlutterMethodCall* call, FlutterResult& result);
void EnsureOverlayInitialized(int64_t overlay_id);
void EnsureGLOverlayInitialized(int64_t overlay_id,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册