Wait for non-empty layout in platform view placeholder (#112402)
diff --git a/packages/flutter/lib/src/widgets/platform_view.dart b/packages/flutter/lib/src/widgets/platform_view.dart index f26d690..982cbc2 100644 --- a/packages/flutter/lib/src/widgets/platform_view.dart +++ b/packages/flutter/lib/src/widgets/platform_view.dart
@@ -877,10 +877,10 @@ return const SizedBox.expand(); } if (!_platformViewCreated) { - // Depending on the implementation, the initial size can be used to size - // the platform view. + // Depending on the implementation, the first non-empty size can be used + // to size the platform view. return _PlatformViewPlaceHolder(onLayout: (Size size) { - if (controller.awaitingCreation) { + if (controller.awaitingCreation && !size.isEmpty) { controller.create(size: size); } });
diff --git a/packages/flutter/test/services/fake_platform_views.dart b/packages/flutter/test/services/fake_platform_views.dart index ea728f6..12b7aaa 100644 --- a/packages/flutter/test/services/fake_platform_views.dart +++ b/packages/flutter/test/services/fake_platform_views.dart
@@ -133,6 +133,9 @@ @override Future<void> create({Size? size}) async { assert(!_createCalledSuccessfully); + if (requiresSize && size != null) { + assert(!size.isEmpty); + } _createCalledSuccessfully = size != null || !requiresSize; }
diff --git a/packages/flutter/test/widgets/platform_view_test.dart b/packages/flutter/test/widgets/platform_view_test.dart index 7af5329..f4fb1d2 100644 --- a/packages/flutter/test/widgets/platform_view_test.dart +++ b/packages/flutter/test/widgets/platform_view_test.dart
@@ -2503,6 +2503,48 @@ ); testWidgets( + 'PlatformViewLink widget should not trigger creation with an empty size', + (WidgetTester tester) async { + late PlatformViewController controller; + + final Widget widget = Center(child: SizedBox( + height: 0, + child: PlatformViewLink( + viewType: 'webview', + onCreatePlatformView: (PlatformViewCreationParams params) { + controller = FakeAndroidViewController(params.id, requiresSize: true); + controller.create(); + // This test should be simulating one of the texture-based display + // modes, where `create` is a no-op when not provided a size, and + // creation is triggered via a later call to setSize, or to `create` + // with a size. + expect(controller.awaitingCreation, true); + return controller; + }, + surfaceFactory: (BuildContext context, PlatformViewController controller) { + return PlatformViewSurface( + gestureRecognizers: const <Factory<OneSequenceGestureRecognizer>>{}, + controller: controller, + hitTestBehavior: PlatformViewHitTestBehavior.opaque, + ); + }, + ) + )); + + await tester.pumpWidget(widget); + + expect( + tester.allWidgets.map((Widget widget) => widget.runtimeType.toString()).toList(), + equals(<String>['Center', 'SizedBox', 'PlatformViewLink', '_PlatformViewPlaceHolder']), + ); + + // 'create' should not have been called by PlatformViewLink, since its + // size is empty. + expect(controller.awaitingCreation, true); + }, + ); + + testWidgets( 'PlatformViewLink calls create when needed for Android texture display modes', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); @@ -2541,6 +2583,9 @@ equals(<String>['PlatformViewLink', '_PlatformViewPlaceHolder']), ); + // Layout should have triggered a create call. Simulate the callback + // that the real controller would make after creation. + expect(controller.awaitingCreation, false); onPlatformViewCreatedCallBack(createdPlatformViewId); await tester.pump(); @@ -2551,7 +2596,6 @@ ); expect(createdPlatformViewId, currentViewId + 1); - expect(controller.awaitingCreation, false); }, );