Platform_views gesture: let flutter view controller be the media to pass the touches. (#8685)

This PR updated the forwarding gesture recognizer to pass the touch events directly to the FlutterViewContoller instead of FlutterView which ensures the touches events are passed to the framework.
This commit is contained in:
Chris Yang 2019-05-10 09:58:33 -07:00 committed by GitHub
parent 710e9edda6
commit 0bc6dc9746
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 30 additions and 15 deletions

View File

@ -22,6 +22,11 @@ void FlutterPlatformViewsController::SetFlutterView(UIView* flutter_view) {
flutter_view_.reset([flutter_view retain]);
}
void FlutterPlatformViewsController::SetFlutterViewController(
UIViewController* flutter_view_controller) {
flutter_view_controller_.reset([flutter_view_controller retain]);
}
void FlutterPlatformViewsController::OnMethodCall(FlutterMethodCall* call, FlutterResult& result) {
if ([[call method] isEqualToString:@"create"]) {
OnCreate(call, result);
@ -80,9 +85,9 @@ void FlutterPlatformViewsController::OnCreate(FlutterMethodCall* call, FlutterRe
arguments:params];
views_[viewId] = fml::scoped_nsobject<NSObject<FlutterPlatformView>>([embedded_view retain]);
FlutterTouchInterceptingView* touch_interceptor =
[[[FlutterTouchInterceptingView alloc] initWithEmbeddedView:embedded_view.view
flutterView:flutter_view_] autorelease];
FlutterTouchInterceptingView* touch_interceptor = [[[FlutterTouchInterceptingView alloc]
initWithEmbeddedView:embedded_view.view
flutterViewController:flutter_view_controller_.get()] autorelease];
touch_interceptors_[viewId] =
fml::scoped_nsobject<FlutterTouchInterceptingView>([touch_interceptor retain]);
@ -355,13 +360,15 @@ void FlutterPlatformViewsController::EnsureGLOverlayInitialized(
// as well. So during this phase as well the ForwardingGestureRecognizer dispatched the events
// directly to the FlutterView.
@interface ForwardingGestureRecognizer : UIGestureRecognizer <UIGestureRecognizerDelegate>
- (instancetype)initWithTarget:(id)target flutterView:(UIView*)flutterView;
- (instancetype)initWithTarget:(id)target
flutterViewController:(UIViewController*)flutterViewController;
@end
@implementation FlutterTouchInterceptingView {
fml::scoped_nsobject<DelayingGestureRecognizer> _delayingRecognizer;
}
- (instancetype)initWithEmbeddedView:(UIView*)embeddedView flutterView:(UIView*)flutterView {
- (instancetype)initWithEmbeddedView:(UIView*)embeddedView
flutterViewController:(UIViewController*)flutterViewController {
self = [super initWithFrame:embeddedView.frame];
if (self) {
self.multipleTouchEnabled = YES;
@ -372,7 +379,7 @@ void FlutterPlatformViewsController::EnsureGLOverlayInitialized(
ForwardingGestureRecognizer* forwardingRecognizer =
[[[ForwardingGestureRecognizer alloc] initWithTarget:self
flutterView:flutterView] autorelease];
flutterViewController:flutterViewController] autorelease];
_delayingRecognizer.reset([[DelayingGestureRecognizer alloc]
initWithTarget:self
@ -446,35 +453,37 @@ void FlutterPlatformViewsController::EnsureGLOverlayInitialized(
@implementation ForwardingGestureRecognizer {
// We can't dispatch events to the framework without this back pointer.
// This is a weak reference, the ForwardingGestureRecognizer is owned by the
// FlutterTouchInterceptingView which is strong referenced only by the FlutterView.
// FlutterTouchInterceptingView which is strong referenced only by the FlutterView,
// which is strongly referenced by the FlutterViewController.
// So this is safe as when FlutterView is deallocated the reference to ForwardingGestureRecognizer
// will go away.
UIView* _flutterView;
UIViewController* _flutterViewController;
// Counting the pointers that has started in one touch sequence.
NSInteger _currentTouchPointersCount;
}
- (instancetype)initWithTarget:(id)target flutterView:(UIView*)flutterView {
- (instancetype)initWithTarget:(id)target
flutterViewController:(UIViewController*)flutterViewController {
self = [super initWithTarget:target action:nil];
if (self) {
self.delegate = self;
_flutterView = flutterView;
_flutterViewController = flutterViewController;
_currentTouchPointersCount = 0;
}
return self;
}
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
[_flutterView touchesBegan:touches withEvent:event];
[_flutterViewController touchesBegan:touches withEvent:event];
_currentTouchPointersCount += touches.count;
}
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
[_flutterView touchesMoved:touches withEvent:event];
[_flutterViewController touchesMoved:touches withEvent:event];
}
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
[_flutterView touchesEnded:touches withEvent:event];
[_flutterViewController touchesEnded:touches withEvent:event];
_currentTouchPointersCount -= touches.count;
// Touches in one touch sequence are sent to the touchesEnded method separately if different
// fingers stop touching the screen at different time. So one touchesEnded method triggering does
@ -486,7 +495,7 @@ void FlutterPlatformViewsController::EnsureGLOverlayInitialized(
}
- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event {
[_flutterView touchesCancelled:touches withEvent:event];
[_flutterViewController touchesCancelled:touches withEvent:event];
_currentTouchPointersCount = 0;
self.state = UIGestureRecognizerStateFailed;
}

View File

@ -18,7 +18,8 @@
// 1. Delay or prevent touch events from arriving the embedded view.
// 2. Dispatching all events that are hittested to the embedded view to the FlutterView.
@interface FlutterTouchInterceptingView : UIView
- (instancetype)initWithEmbeddedView:(UIView*)embeddedView flutterView:(UIView*)flutterView;
- (instancetype)initWithEmbeddedView:(UIView*)embeddedView
flutterViewController:(UIViewController*)flutterViewController;
// Stop delaying any active touch sequence (and let it arrive the embedded view).
- (void)releaseGesture;
@ -52,6 +53,8 @@ class FlutterPlatformViewsController {
void SetFlutterView(UIView* flutter_view);
void SetFlutterViewController(UIViewController* flutter_view_controller);
void RegisterViewFactory(NSObject<FlutterPlatformViewFactory>* factory, NSString* factoryId);
void SetFrameSize(SkISize frame_size);
@ -81,6 +84,7 @@ class FlutterPlatformViewsController {
private:
fml::scoped_nsobject<FlutterMethodChannel> channel_;
fml::scoped_nsobject<UIView> flutter_view_;
fml::scoped_nsobject<UIViewController> flutter_view_controller_;
std::map<std::string, fml::scoped_nsobject<NSObject<FlutterPlatformViewFactory>>> factories_;
std::map<int64_t, fml::scoped_nsobject<NSObject<FlutterPlatformView>>> views_;
std::map<int64_t, fml::scoped_nsobject<FlutterTouchInterceptingView>> touch_interceptors_;

View File

@ -382,10 +382,12 @@ NSNotificationName const FlutterSemanticsUpdateNotification = @"FlutterSemantics
if (appeared) {
[self installSplashScreenViewCallback];
[_engine.get() platformViewsController] -> SetFlutterView(_flutterView.get());
[_engine.get() platformViewsController] -> SetFlutterViewController(self);
[_engine.get() platformView] -> NotifyCreated();
} else {
[_engine.get() platformView] -> NotifyDestroyed();
[_engine.get() platformViewsController] -> SetFlutterView(nullptr);
[_engine.get() platformViewsController] -> SetFlutterViewController(nullptr);
}
}