mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Always set change type to cancel with touchesCancelled on iOS platform view (#24333)
This commit is contained in:
parent
7e48c42679
commit
b9ecd8aca6
@ -15,6 +15,7 @@
|
|||||||
#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterChannels.h"
|
#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterChannels.h"
|
||||||
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h"
|
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterOverlayView.h"
|
||||||
#import "flutter/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.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/ios_surface.h"
|
#import "flutter/shell/platform/darwin/ios/ios_surface.h"
|
||||||
#import "flutter/shell/platform/darwin/ios/ios_surface_gl.h"
|
#import "flutter/shell/platform/darwin/ios/ios_surface_gl.h"
|
||||||
|
|
||||||
@ -938,7 +939,12 @@ void FlutterPlatformViewsController::ResetFrameState() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event {
|
- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event {
|
||||||
[_flutterViewController.get() touchesCancelled:touches withEvent:event];
|
// In the event of platform view is removed, iOS generates a "stationary" change type instead of
|
||||||
|
// "cancelled" change type.
|
||||||
|
// Flutter needs all the cancelled touches to be "cancelled" change types in order to correctly
|
||||||
|
// handle gesture sequence.
|
||||||
|
// We always override the change type to "cancelled".
|
||||||
|
[((FlutterViewController*)_flutterViewController.get()) forceTouchesCancelled:touches];
|
||||||
_currentTouchPointersCount -= touches.count;
|
_currentTouchPointersCount -= touches.count;
|
||||||
if (_currentTouchPointersCount == 0) {
|
if (_currentTouchPointersCount == 0) {
|
||||||
self.state = UIGestureRecognizerStateFailed;
|
self.state = UIGestureRecognizerStateFailed;
|
||||||
|
|||||||
@ -626,7 +626,7 @@ fml::RefPtr<fml::TaskRunner> CreateNewThread(std::string name) {
|
|||||||
// Before setting flutter view controller, events are not dispatched.
|
// Before setting flutter view controller, events are not dispatched.
|
||||||
NSSet* touches1 = [[[NSSet alloc] init] autorelease];
|
NSSet* touches1 = [[[NSSet alloc] init] autorelease];
|
||||||
id event1 = OCMClassMock([UIEvent class]);
|
id event1 = OCMClassMock([UIEvent class]);
|
||||||
id mockFlutterViewContoller = OCMClassMock([UIViewController class]);
|
id mockFlutterViewContoller = OCMClassMock([FlutterViewController class]);
|
||||||
[forwardGectureRecognizer touchesBegan:touches1 withEvent:event1];
|
[forwardGectureRecognizer touchesBegan:touches1 withEvent:event1];
|
||||||
OCMReject([mockFlutterViewContoller touchesBegan:touches1 withEvent:event1]);
|
OCMReject([mockFlutterViewContoller touchesBegan:touches1 withEvent:event1]);
|
||||||
|
|
||||||
@ -684,7 +684,7 @@ fml::RefPtr<fml::TaskRunner> CreateNewThread(std::string name) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
id mockFlutterViewContoller = OCMClassMock([UIViewController class]);
|
id mockFlutterViewContoller = OCMClassMock([FlutterViewController class]);
|
||||||
{
|
{
|
||||||
// ***** Sequence 1, finishing touch event with touchEnded ***** //
|
// ***** Sequence 1, finishing touch event with touchEnded ***** //
|
||||||
flutterPlatformViewsController->SetFlutterViewController(mockFlutterViewContoller);
|
flutterPlatformViewsController->SetFlutterViewController(mockFlutterViewContoller);
|
||||||
@ -739,7 +739,7 @@ fml::RefPtr<fml::TaskRunner> CreateNewThread(std::string name) {
|
|||||||
NSSet* touches3 = [[[NSSet alloc] init] autorelease];
|
NSSet* touches3 = [[[NSSet alloc] init] autorelease];
|
||||||
id event3 = OCMClassMock([UIEvent class]);
|
id event3 = OCMClassMock([UIEvent class]);
|
||||||
[forwardGectureRecognizer touchesCancelled:touches3 withEvent:event3];
|
[forwardGectureRecognizer touchesCancelled:touches3 withEvent:event3];
|
||||||
OCMVerify([mockFlutterViewContoller touchesCancelled:touches3 withEvent:event3]);
|
OCMVerify([mockFlutterViewContoller forceTouchesCancelled:touches3]);
|
||||||
|
|
||||||
// Now the 2nd touch sequence should not be allowed.
|
// Now the 2nd touch sequence should not be allowed.
|
||||||
NSSet* touches4 = [[[NSSet alloc] init] autorelease];
|
NSSet* touches4 = [[[NSSet alloc] init] autorelease];
|
||||||
@ -803,7 +803,7 @@ fml::RefPtr<fml::TaskRunner> CreateNewThread(std::string name) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
id mockFlutterViewContoller = OCMClassMock([UIViewController class]);
|
id mockFlutterViewContoller = OCMClassMock([FlutterViewController class]);
|
||||||
|
|
||||||
flutterPlatformViewsController->SetFlutterViewController(mockFlutterViewContoller);
|
flutterPlatformViewsController->SetFlutterViewController(mockFlutterViewContoller);
|
||||||
|
|
||||||
@ -866,6 +866,66 @@ fml::RefPtr<fml::TaskRunner> CreateNewThread(std::string name) {
|
|||||||
flutterPlatformViewsController->Reset();
|
flutterPlatformViewsController->Reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)testFlutterPlatformViewTouchesCancelledEventAreForcedToBeCancelled {
|
||||||
|
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 flutterPlatformViewsController = std::make_shared<flutter::FlutterPlatformViewsController>();
|
||||||
|
auto platform_view = std::make_unique<flutter::PlatformViewIOS>(
|
||||||
|
/*delegate=*/mock_delegate,
|
||||||
|
/*rendering_api=*/flutter::IOSRenderingAPI::kSoftware,
|
||||||
|
/*platform_views_controller=*/flutterPlatformViewsController,
|
||||||
|
/*task_runners=*/runners);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
id mockFlutterViewContoller = OCMClassMock([FlutterViewController class]);
|
||||||
|
|
||||||
|
flutterPlatformViewsController->SetFlutterViewController(mockFlutterViewContoller);
|
||||||
|
|
||||||
|
NSSet* touches1 = [NSSet setWithObject:@1];
|
||||||
|
id event1 = OCMClassMock([UIEvent class]);
|
||||||
|
[forwardGectureRecognizer touchesBegan:touches1 withEvent:event1];
|
||||||
|
|
||||||
|
[forwardGectureRecognizer touchesCancelled:touches1 withEvent:event1];
|
||||||
|
OCMVerify([mockFlutterViewContoller forceTouchesCancelled:touches1]);
|
||||||
|
|
||||||
|
flutterPlatformViewsController->Reset();
|
||||||
|
}
|
||||||
|
|
||||||
- (void)testFlutterPlatformViewControllerSubmitFrameWithoutFlutterViewNotCrashing {
|
- (void)testFlutterPlatformViewControllerSubmitFrameWithoutFlutterViewNotCrashing {
|
||||||
flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
|
flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
|
||||||
auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
|
auto thread_task_runner = CreateNewThread("FlutterPlatformViewsTest");
|
||||||
|
|||||||
@ -947,6 +947,11 @@ static flutter::PointerData::DeviceKind DeviceKindFromTouchType(UITouch* touch)
|
|||||||
[self dispatchTouches:touches pointerDataChangeOverride:nullptr];
|
[self dispatchTouches:touches pointerDataChangeOverride:nullptr];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)forceTouchesCancelled:(NSSet*)touches {
|
||||||
|
flutter::PointerData::Change cancel = flutter::PointerData::Change::kCancel;
|
||||||
|
[self dispatchTouches:touches pointerDataChangeOverride:&cancel];
|
||||||
|
}
|
||||||
|
|
||||||
#pragma mark - Handle view resizing
|
#pragma mark - Handle view resizing
|
||||||
|
|
||||||
- (void)updateViewportMetrics {
|
- (void)updateViewportMetrics {
|
||||||
|
|||||||
@ -29,6 +29,9 @@ extern NSNotificationName const FlutterViewControllerShowHomeIndicator;
|
|||||||
- (fml::WeakPtr<FlutterViewController>)getWeakPtr;
|
- (fml::WeakPtr<FlutterViewController>)getWeakPtr;
|
||||||
- (std::shared_ptr<flutter::FlutterPlatformViewsController>&)platformViewsController;
|
- (std::shared_ptr<flutter::FlutterPlatformViewsController>&)platformViewsController;
|
||||||
- (FlutterRestorationPlugin*)restorationPlugin;
|
- (FlutterRestorationPlugin*)restorationPlugin;
|
||||||
|
// Send touches to the Flutter Engine while forcing the change type to be cancelled.
|
||||||
|
// The `phase`s in `touches` are ignored.
|
||||||
|
- (void)forceTouchesCancelled:(NSSet*)touches;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user