Skip to content

Commit

Permalink
[platform_view]fix overlapped platform view not touchable
Browse files Browse the repository at this point in the history
  • Loading branch information
hellohuanlin committed Feb 15, 2023
1 parent d28cbf4 commit 4a6b7ac
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 14 deletions.
19 changes: 5 additions & 14 deletions shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm
Original file line number Diff line number Diff line change
Expand Up @@ -786,29 +786,20 @@ static bool ClipRRectContainsPlatformViewBoundingRect(const SkRRect& clip_rrect,
void FlutterPlatformViewsController::BringLayersIntoView(LayersMap layer_map) {
FML_DCHECK(flutter_view_);
UIView* flutter_view = flutter_view_.get();
auto zIndex = 0;
// Clear the `active_composition_order_`, which will be populated down below.
active_composition_order_.clear();
for (size_t i = 0; i < composition_order_.size(); i++) {
int64_t platform_view_id = composition_order_[i];
std::vector<std::shared_ptr<FlutterPlatformViewLayer>> layers = layer_map[platform_view_id];
UIView* platform_view_root = root_views_[platform_view_id].get();

if (platform_view_root.superview != flutter_view) {
[flutter_view addSubview:platform_view_root];
}
// `addSubview` will automatically reorder subview if it is already added.
// No need to manually remove or reorder subview.
// Simply having a higher zPosition is not enough since it does not affect touch behavior.
[flutter_view addSubview:platform_view_root];
// Make sure the platform_view_root is higher than the last platform_view_root in
// composition_order_.
platform_view_root.layer.zPosition = zIndex++;

for (const std::shared_ptr<FlutterPlatformViewLayer>& layer : layers) {
if ([layer->overlay_view_wrapper.get() superview] != flutter_view) {
[flutter_view addSubview:layer->overlay_view_wrapper];
}
// Make sure all the overlays are higher than the platform view.
layer->overlay_view_wrapper.get().layer.zPosition = zIndex++;
FML_DCHECK(layer->overlay_view_wrapper.get().layer.zPosition >
platform_view_root.layer.zPosition);
[flutter_view addSubview:layer->overlay_view_wrapper];
}
active_composition_order_.push_back(platform_view_id);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2345,6 +2345,105 @@ - (void)testFlutterPlatformViewControllerBeginFrameShouldResetCompisitionOrder {
XCTAssertEqual(flutterPlatformViewsController->GetCurrentBuilders().size(), 1UL);
}

- (void)testFlutterPlatformViewControllerSubmitFrameShouldOrderSubviewsCorrectly {
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);

UIView* mockFlutterView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 500, 500)] autorelease];
flutterPlatformViewsController->SetFlutterView(mockFlutterView);

FlutterPlatformViewsTestMockFlutterPlatformFactory* factory =
[[FlutterPlatformViewsTestMockFlutterPlatformFactory new] autorelease];
flutterPlatformViewsController->RegisterViewFactory(
factory, @"MockFlutterPlatformView",
FlutterPlatformViewGestureRecognizersBlockingPolicyEager);
FlutterResult result = ^(id result) {
};
flutterPlatformViewsController->OnMethodCall(
[FlutterMethodCall
methodCallWithMethodName:@"create"
arguments:@{@"id" : @0, @"viewType" : @"MockFlutterPlatformView"}],
result);
UIView* view1 = gMockPlatformView;

// This overwrites `gMockPlatformView` to another view.
flutterPlatformViewsController->OnMethodCall(
[FlutterMethodCall
methodCallWithMethodName:@"create"
arguments:@{@"id" : @1, @"viewType" : @"MockFlutterPlatformView"}],
result);
UIView* view2 = gMockPlatformView;

flutterPlatformViewsController->BeginFrame(SkISize::Make(300, 300));
flutter::MutatorsStack stack;
SkMatrix finalMatrix;
auto embeddedViewParams1 =
std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(300, 300), stack);
flutterPlatformViewsController->PrerollCompositeEmbeddedView(0, std::move(embeddedViewParams1));
flutterPlatformViewsController->CompositeEmbeddedView(0);

auto embeddedViewParams2 =
std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(500, 500), stack);
flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams2));
flutterPlatformViewsController->CompositeEmbeddedView(1);

// SKSurface is required if the root FlutterView is present.
const SkImageInfo image_info = SkImageInfo::MakeN32Premul(1000, 1000);
sk_sp<SkSurface> mock_sk_surface = SkSurface::MakeRaster(image_info);
flutter::SurfaceFrame::FramebufferInfo framebuffer_info;
auto mock_surface = std::make_unique<flutter::SurfaceFrame>(
std::move(mock_sk_surface), framebuffer_info,
[](const flutter::SurfaceFrame& surface_frame, SkCanvas* canvas) { return true; },
/*frame_size=*/SkISize::Make(800, 600));
XCTAssertTrue(
flutterPlatformViewsController->SubmitFrame(nullptr, nullptr, std::move(mock_surface)));

// platform view is wrapped by touch interceptor, which itself is wrapped by clipping view.
UIView* clippingView1 = view1.superview.superview;
UIView* clippingView2 = view2.superview.superview;
UIView* flutterView = clippingView1.superview;

XCTAssert([flutterView.subviews indexOfObject:clippingView1] < [flutterView.subviews
indexOfObject:clippingView2],
@"The first clipping view should be added before the second clipping view.");

// Process the second frame in opposite order.
// Need to recreate these params since they are `std::move`ed.
flutterPlatformViewsController->BeginFrame(SkISize::Make(300, 300));
embeddedViewParams2 =
std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(500, 500), stack);
flutterPlatformViewsController->PrerollCompositeEmbeddedView(1, std::move(embeddedViewParams2));
flutterPlatformViewsController->CompositeEmbeddedView(1);

embeddedViewParams1 =
std::make_unique<flutter::EmbeddedViewParams>(finalMatrix, SkSize::Make(300, 300), stack);
flutterPlatformViewsController->PrerollCompositeEmbeddedView(0, std::move(embeddedViewParams1));
flutterPlatformViewsController->CompositeEmbeddedView(0);

mock_sk_surface = SkSurface::MakeRaster(image_info);
mock_surface = std::make_unique<flutter::SurfaceFrame>(
std::move(mock_sk_surface), framebuffer_info,
[](const flutter::SurfaceFrame& surface_frame, SkCanvas* canvas) { return true; },
/*frame_size=*/SkISize::Make(800, 600));
XCTAssertTrue(
flutterPlatformViewsController->SubmitFrame(nullptr, nullptr, std::move(mock_surface)));

XCTAssert([flutterView.subviews indexOfObject:clippingView1] >
[flutterView.subviews indexOfObject:clippingView2],
@"The first clipping view should be added after the second clipping view.");
}

- (void)testThreadMergeAtEndFrame {
flutter::FlutterPlatformViewsTestMockPlatformViewDelegate mock_delegate;
auto thread_task_runner_platform = CreateNewThread("FlutterPlatformViewsTest1");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
FLUTTER_ENGINE[arch=x86_64]=ios_debug_sim_unopt
FLUTTER_ENGINE[arch=arm64]=ios_debug_sim_unopt_arm64
FLUTTER_ENGINE=ios_debug_sim_unopt

0 comments on commit 4a6b7ac

Please sign in to comment.