mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
The ForwardingGestureRecognizers to have back reference to the PlatformViewsController so it can access FlutterViewController when its available (#20708)
This commit is contained in:
parent
9939c26bd2
commit
1c13abaab1
@ -107,6 +107,10 @@ void FlutterPlatformViewsController::SetFlutterViewController(
|
||||
flutter_view_controller_.reset([flutter_view_controller retain]);
|
||||
}
|
||||
|
||||
UIViewController* FlutterPlatformViewsController::getFlutterViewController() {
|
||||
return flutter_view_controller_.get();
|
||||
}
|
||||
|
||||
void FlutterPlatformViewsController::OnMethodCall(FlutterMethodCall* call, FlutterResult& result) {
|
||||
if ([[call method] isEqualToString:@"create"]) {
|
||||
OnCreate(call, result);
|
||||
@ -161,7 +165,7 @@ void FlutterPlatformViewsController::OnCreate(FlutterMethodCall* call, FlutterRe
|
||||
|
||||
FlutterTouchInterceptingView* touch_interceptor = [[[FlutterTouchInterceptingView alloc]
|
||||
initWithEmbeddedView:embedded_view.view
|
||||
flutterViewController:flutter_view_controller_.get()
|
||||
platformViewsController:GetWeakPtr()
|
||||
gestureRecognizersBlockingPolicy:gesture_recognizers_blocking_policies[viewType]]
|
||||
autorelease];
|
||||
|
||||
@ -701,7 +705,8 @@ void FlutterPlatformViewsController::DisposeViews() {
|
||||
// directly to the FlutterView.
|
||||
@interface ForwardingGestureRecognizer : UIGestureRecognizer <UIGestureRecognizerDelegate>
|
||||
- (instancetype)initWithTarget:(id)target
|
||||
flutterViewController:(UIViewController*)flutterViewController;
|
||||
platformViewsController:
|
||||
(fml::WeakPtr<flutter::FlutterPlatformViewsController>)platformViewsController;
|
||||
@end
|
||||
|
||||
@implementation FlutterTouchInterceptingView {
|
||||
@ -709,7 +714,8 @@ void FlutterPlatformViewsController::DisposeViews() {
|
||||
FlutterPlatformViewGestureRecognizersBlockingPolicy _blockingPolicy;
|
||||
}
|
||||
- (instancetype)initWithEmbeddedView:(UIView*)embeddedView
|
||||
flutterViewController:(UIViewController*)flutterViewController
|
||||
platformViewsController:
|
||||
(fml::WeakPtr<flutter::FlutterPlatformViewsController>)platformViewsController
|
||||
gestureRecognizersBlockingPolicy:
|
||||
(FlutterPlatformViewGestureRecognizersBlockingPolicy)blockingPolicy {
|
||||
self = [super initWithFrame:embeddedView.frame];
|
||||
@ -720,9 +726,9 @@ void FlutterPlatformViewsController::DisposeViews() {
|
||||
|
||||
[self addSubview:embeddedView];
|
||||
|
||||
ForwardingGestureRecognizer* forwardingRecognizer =
|
||||
[[[ForwardingGestureRecognizer alloc] initWithTarget:self
|
||||
flutterViewController:flutterViewController] autorelease];
|
||||
ForwardingGestureRecognizer* forwardingRecognizer = [[[ForwardingGestureRecognizer alloc]
|
||||
initWithTarget:self
|
||||
platformViewsController:std::move(platformViewsController)] autorelease];
|
||||
|
||||
_delayingRecognizer.reset([[DelayingGestureRecognizer alloc]
|
||||
initWithTarget:self
|
||||
@ -833,39 +839,42 @@ void FlutterPlatformViewsController::DisposeViews() {
|
||||
@end
|
||||
|
||||
@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,
|
||||
// which is strongly referenced by the FlutterViewController.
|
||||
// So this is safe as when FlutterView is deallocated the reference to ForwardingGestureRecognizer
|
||||
// will go away.
|
||||
UIViewController* _flutterViewController;
|
||||
// Weak reference to FlutterPlatformViewsController. The FlutterPlatformViewsController has
|
||||
// a reference to the FlutterViewController, where we can dispatch pointer events to.
|
||||
//
|
||||
// The lifecycle of FlutterPlatformViewsController is bind to FlutterEngine, which should always
|
||||
// outlives the FlutterViewController. And ForwardingGestureRecognizer is owned by a subview of
|
||||
// FlutterView, so the ForwardingGestureRecognizer never out lives FlutterViewController.
|
||||
// Therefore, `_platformViewsController` should never be nullptr.
|
||||
fml::WeakPtr<flutter::FlutterPlatformViewsController> _platformViewsController;
|
||||
// Counting the pointers that has started in one touch sequence.
|
||||
NSInteger _currentTouchPointersCount;
|
||||
}
|
||||
|
||||
- (instancetype)initWithTarget:(id)target
|
||||
flutterViewController:(UIViewController*)flutterViewController {
|
||||
platformViewsController:
|
||||
(fml::WeakPtr<flutter::FlutterPlatformViewsController>)platformViewsController {
|
||||
self = [super initWithTarget:target action:nil];
|
||||
if (self) {
|
||||
self.delegate = self;
|
||||
_flutterViewController = flutterViewController;
|
||||
FML_DCHECK(platformViewsController.get() != nullptr);
|
||||
_platformViewsController = std::move(platformViewsController);
|
||||
_currentTouchPointersCount = 0;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event {
|
||||
[_flutterViewController touchesBegan:touches withEvent:event];
|
||||
[_platformViewsController.get()->getFlutterViewController() touchesBegan:touches withEvent:event];
|
||||
_currentTouchPointersCount += touches.count;
|
||||
}
|
||||
|
||||
- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {
|
||||
[_flutterViewController touchesMoved:touches withEvent:event];
|
||||
[_platformViewsController.get()->getFlutterViewController() touchesMoved:touches withEvent:event];
|
||||
}
|
||||
|
||||
- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
|
||||
[_flutterViewController touchesEnded:touches withEvent:event];
|
||||
[_platformViewsController.get()->getFlutterViewController() 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
|
||||
@ -877,7 +886,8 @@ void FlutterPlatformViewsController::DisposeViews() {
|
||||
}
|
||||
|
||||
- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event {
|
||||
[_flutterViewController touchesCancelled:touches withEvent:event];
|
||||
[_platformViewsController.get()->getFlutterViewController() touchesCancelled:touches
|
||||
withEvent:event];
|
||||
_currentTouchPointersCount = 0;
|
||||
self.state = UIGestureRecognizerStateFailed;
|
||||
}
|
||||
|
||||
@ -7,7 +7,9 @@
|
||||
#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterBinaryMessenger.h"
|
||||
#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterMacros.h"
|
||||
#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterPlatformViews.h"
|
||||
#import "flutter/shell/platform/darwin/ios/framework/Headers/FlutterViewController.h"
|
||||
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h"
|
||||
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterViewController_Internal.h"
|
||||
#import "flutter/shell/platform/darwin/ios/platform_view_ios.h"
|
||||
#import "third_party/ocmock/Source/OCMock/OCMock.h"
|
||||
|
||||
@ -508,6 +510,70 @@ fml::RefPtr<fml::TaskRunner> CreateNewThread(std::string name) {
|
||||
flutterPlatformViewsController->Reset();
|
||||
}
|
||||
|
||||
- (void)testSetFlutterViewControllerAfterCreateCanStillDispatchTouchEvents {
|
||||
flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
|
||||
auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
|
||||
flutter::TaskRunners runners(/*label=*/self.name.UTF8String,
|
||||
/*platform=*/thread_task_runner,
|
||||
/*raster=*/thread_task_runner,
|
||||
/*ui=*/thread_task_runner,
|
||||
/*io=*/thread_task_runner);
|
||||
auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
|
||||
/*delegate=*/mock_delegate,
|
||||
/*rendering_api=*/flutter::IOSRenderingAPI::kSoftware,
|
||||
/*task_runners=*/runners);
|
||||
|
||||
auto flutterPlatformViewsController = std::make_unique<flutter::FlutterPlatformViewsController>();
|
||||
|
||||
FlutterPlatformViewsTestMockFlutterPlatformFactory* factory =
|
||||
[[FlutterPlatformViewsTestMockFlutterPlatformFactory new] autorelease];
|
||||
flutterPlatformViewsController->RegisterViewFactory(
|
||||
factory, @"MockFlutterPlatformView",
|
||||
FlutterPlatformViewGestureRecognizersBlockingPolicyEager);
|
||||
FlutterResult result = ^(id result) {
|
||||
};
|
||||
flutterPlatformViewsController->OnMethodCall(
|
||||
[FlutterMethodCall
|
||||
methodCallWithMethodName:@"create"
|
||||
arguments:@{@"id" : @2, @"viewType" : @"MockFlutterPlatformView"}],
|
||||
result);
|
||||
|
||||
XCTAssertNotNil(gMockPlatformView);
|
||||
|
||||
// Find touch inteceptor view
|
||||
UIView* touchInteceptorView = gMockPlatformView;
|
||||
while (touchInteceptorView != nil &&
|
||||
![touchInteceptorView isKindOfClass:[FlutterTouchInterceptingView class]]) {
|
||||
touchInteceptorView = touchInteceptorView.superview;
|
||||
}
|
||||
XCTAssertNotNil(touchInteceptorView);
|
||||
|
||||
// Find ForwardGestureRecognizer
|
||||
UIGestureRecognizer* forwardGectureRecognizer = nil;
|
||||
for (UIGestureRecognizer* gestureRecognizer in touchInteceptorView.gestureRecognizers) {
|
||||
if ([gestureRecognizer isKindOfClass:NSClassFromString(@"ForwardingGestureRecognizer")]) {
|
||||
forwardGectureRecognizer = gestureRecognizer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Before setting flutter view controller, events are not dispatched.
|
||||
NSSet* touches1 = OCMClassMock([NSSet class]);
|
||||
UIEvent* event1 = OCMClassMock([UIEvent class]);
|
||||
UIViewController* mockFlutterViewContoller = OCMClassMock([UIViewController class]);
|
||||
[forwardGectureRecognizer touchesBegan:touches1 withEvent:event1];
|
||||
OCMReject([mockFlutterViewContoller touchesBegan:touches1 withEvent:event1]);
|
||||
|
||||
// Set flutter view controller allows events to be dispatched.
|
||||
NSSet* touches2 = OCMClassMock([NSSet class]);
|
||||
UIEvent* event2 = OCMClassMock([UIEvent class]);
|
||||
flutterPlatformViewsController->SetFlutterViewController(mockFlutterViewContoller);
|
||||
[forwardGectureRecognizer touchesBegan:touches2 withEvent:event2];
|
||||
OCMVerify([mockFlutterViewContoller touchesBegan:touches2 withEvent:event2]);
|
||||
|
||||
flutterPlatformViewsController->Reset();
|
||||
}
|
||||
|
||||
- (int)alphaOfPoint:(CGPoint)point onView:(UIView*)view {
|
||||
unsigned char pixel[4] = {0};
|
||||
|
||||
|
||||
@ -16,6 +16,8 @@
|
||||
#include "flutter/shell/platform/darwin/ios/ios_context.h"
|
||||
#include "third_party/skia/include/core/SkPictureRecorder.h"
|
||||
|
||||
@class FlutterTouchInterceptingView;
|
||||
|
||||
// A UIView that acts as a clipping mask for the |ChildClippingView|.
|
||||
//
|
||||
// On the [UIView drawRect:] method, this view performs a series of clipping operations and sets the
|
||||
@ -43,24 +45,6 @@
|
||||
|
||||
@end
|
||||
|
||||
// A UIView that is used as the parent for embedded UIViews.
|
||||
//
|
||||
// This view has 2 roles:
|
||||
// 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
|
||||
flutterViewController:(UIViewController*)flutterViewController
|
||||
gestureRecognizersBlockingPolicy:
|
||||
(FlutterPlatformViewGestureRecognizersBlockingPolicy)blockingPolicy;
|
||||
|
||||
// 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
|
||||
|
||||
// The parent view handles clipping to its subviews.
|
||||
@interface ChildClippingView : UIView
|
||||
|
||||
@ -143,10 +127,14 @@ class FlutterPlatformViewsController {
|
||||
|
||||
~FlutterPlatformViewsController();
|
||||
|
||||
fml::WeakPtr<flutter::FlutterPlatformViewsController> GetWeakPtr();
|
||||
|
||||
void SetFlutterView(UIView* flutter_view);
|
||||
|
||||
void SetFlutterViewController(UIViewController* flutter_view_controller);
|
||||
|
||||
UIViewController* getFlutterViewController();
|
||||
|
||||
void RegisterViewFactory(
|
||||
NSObject<FlutterPlatformViewFactory>* factory,
|
||||
NSString* factoryId,
|
||||
@ -255,6 +243,8 @@ class FlutterPlatformViewsController {
|
||||
std::map<std::string, FlutterPlatformViewGestureRecognizersBlockingPolicy>
|
||||
gesture_recognizers_blocking_policies;
|
||||
|
||||
std::unique_ptr<fml::WeakPtrFactory<FlutterPlatformViewsController>> weak_factory_;
|
||||
|
||||
void OnCreate(FlutterMethodCall* call, FlutterResult& result);
|
||||
void OnDispose(FlutterMethodCall* call, FlutterResult& result);
|
||||
void OnAcceptGesture(FlutterMethodCall* call, FlutterResult& result);
|
||||
@ -313,4 +303,23 @@ class FlutterPlatformViewsController {
|
||||
|
||||
} // namespace flutter
|
||||
|
||||
// A UIView that is used as the parent for embedded UIViews.
|
||||
//
|
||||
// This view has 2 roles:
|
||||
// 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
|
||||
platformViewsController:
|
||||
(fml::WeakPtr<flutter::FlutterPlatformViewsController>)platformViewsController
|
||||
gestureRecognizersBlockingPolicy:
|
||||
(FlutterPlatformViewGestureRecognizersBlockingPolicy)blockingPolicy;
|
||||
|
||||
// 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
|
||||
|
||||
#endif // FLUTTER_SHELL_PLATFORM_DARWIN_IOS_FRAMEWORK_SOURCE_FLUTTERPLATFORMVIEWS_INTERNAL_H_
|
||||
|
||||
@ -24,10 +24,15 @@ FlutterPlatformViewLayer::FlutterPlatformViewLayer(
|
||||
FlutterPlatformViewLayer::~FlutterPlatformViewLayer() = default;
|
||||
|
||||
FlutterPlatformViewsController::FlutterPlatformViewsController()
|
||||
: layer_pool_(std::make_unique<FlutterPlatformViewLayerPool>()){};
|
||||
: layer_pool_(std::make_unique<FlutterPlatformViewLayerPool>()),
|
||||
weak_factory_(std::make_unique<fml::WeakPtrFactory<FlutterPlatformViewsController>>(this)){};
|
||||
|
||||
FlutterPlatformViewsController::~FlutterPlatformViewsController() = default;
|
||||
|
||||
fml::WeakPtr<flutter::FlutterPlatformViewsController> FlutterPlatformViewsController::GetWeakPtr() {
|
||||
return weak_factory_->GetWeakPtr();
|
||||
}
|
||||
|
||||
CATransform3D GetCATransform3DFromSkMatrix(const SkMatrix& matrix) {
|
||||
// Skia only supports 2D transform so we don't map z.
|
||||
CATransform3D transform = CATransform3DIdentity;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user