From b0188cd18274d44af9997440fa11fe29cbc504f6 Mon Sep 17 00:00:00 2001 From: Mouad Debbar Date: Thu, 15 Jun 2023 14:00:25 -0400 Subject: [PATCH] [web] Pass creation params to the platform view factory (#128146) This concludes step 1 of the `HtmlElementView` improvements. It's now possible to pass creation params to platform view factories directly from `HtmlElementView`. Here's a sample app using a single factory to render platform views in different colors:
Code sample ```dart import 'dart:js_interop'; import 'dart:ui_web' as ui_web; import 'package:flutter/material.dart'; import 'package:web/web.dart' as web; void main() { runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Platform View Demo', home: Scaffold( appBar: AppBar( title: Text('Platform View Demo'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ BoxWrapper('red'), BoxWrapper(null), BoxWrapper('blue'), ], ), ), ), ); } } bool isRegistered = false; class BoxWrapper extends StatelessWidget { const BoxWrapper(this.cssColor); final String? cssColor; void register() { if (isRegistered) return; isRegistered = true; ui_web.platformViewRegistry.registerViewFactory('my-platform-view', ( id, { Object? params, }) { params as String?; final element = web.document.createElement('div'.toJS) as web.HTMLElement; element.textContent = 'Platform View'.toJS; element.style ..lineHeight = '100px'.toJS ..fontSize = '24px'.toJS ..backgroundColor = (params ?? 'pink').toJS ..textAlign = 'center'.toJS; return element; }); } @override Widget build(BuildContext context) { register(); return SizedBox( width: 200, height: 100, child: Card( child: HtmlElementView( viewType: 'my-platform-view', creationParams: cssColor, ), ), ); } } ```
![image](https://github.com/flutter/flutter/assets/1278212/4b62ed8b-2314-49d6-9b4a-5da849bf2a48) Depends on https://github.com/flutter/engine/pull/42255 Part of https://github.com/flutter/flutter/issues/127030 --- .../lib/src/widgets/platform_view.dart | 14 +++++++- .../test/services/fake_platform_views.dart | 13 ++++--- .../test/widgets/html_element_view_test.dart | 36 +++++++++++++++++++ 3 files changed, 57 insertions(+), 6 deletions(-) diff --git a/packages/flutter/lib/src/widgets/platform_view.dart b/packages/flutter/lib/src/widgets/platform_view.dart index 55653d2af2..32ce829a7f 100644 --- a/packages/flutter/lib/src/widgets/platform_view.dart +++ b/packages/flutter/lib/src/widgets/platform_view.dart @@ -345,6 +345,7 @@ class HtmlElementView extends StatelessWidget { super.key, required this.viewType, this.onPlatformViewCreated, + this.creationParams, }) : assert(kIsWeb, 'HtmlElementView is only available on Flutter Web.'); /// The unique identifier for the HTML view type to be embedded by this widget. @@ -357,6 +358,9 @@ class HtmlElementView extends StatelessWidget { /// May be null. final PlatformViewCreatedCallback? onPlatformViewCreated; + /// Passed as the 2nd argument (i.e. `params`) of the registered view factory. + final Object? creationParams; + @override Widget build(BuildContext context) { return PlatformViewLink( @@ -374,7 +378,11 @@ class HtmlElementView extends StatelessWidget { /// Creates the controller and kicks off its initialization. _HtmlElementViewController _createHtmlElementView(PlatformViewCreationParams params) { - final _HtmlElementViewController controller = _HtmlElementViewController(params.id, viewType); + final _HtmlElementViewController controller = _HtmlElementViewController( + params.id, + viewType, + creationParams, + ); controller._initialize().then((_) { params.onPlatformViewCreated(params.id); onPlatformViewCreated?.call(params.id); @@ -387,6 +395,7 @@ class _HtmlElementViewController extends PlatformViewController { _HtmlElementViewController( this.viewId, this.viewType, + this.creationParams, ); @override @@ -397,12 +406,15 @@ class _HtmlElementViewController extends PlatformViewController { /// A PlatformViewFactory for this type must have been registered. final String viewType; + final dynamic creationParams; + bool _initialized = false; Future _initialize() async { final Map args = { 'id': viewId, 'viewType': viewType, + 'params': creationParams, }; await SystemChannels.platform_views.invokeMethod('create', args); _initialized = true; diff --git a/packages/flutter/test/services/fake_platform_views.dart b/packages/flutter/test/services/fake_platform_views.dart index 0cf5f36776..7d85e93733 100644 --- a/packages/flutter/test/services/fake_platform_views.dart +++ b/packages/flutter/test/services/fake_platform_views.dart @@ -503,6 +503,7 @@ class FakeHtmlPlatformViewsController { final Map args = call.arguments as Map; final int id = args['id'] as int; final String viewType = args['viewType'] as String; + final Object? params = args['params']; if (_views.containsKey(id)) { throw PlatformException( @@ -522,7 +523,7 @@ class FakeHtmlPlatformViewsController { await createCompleter!.future; } - _views[id] = FakeHtmlPlatformView(id, viewType); + _views[id] = FakeHtmlPlatformView(id, viewType, params); return Future.sync(() => null); } @@ -658,10 +659,11 @@ class FakeUiKitView { @immutable class FakeHtmlPlatformView { - const FakeHtmlPlatformView(this.id, this.type); + const FakeHtmlPlatformView(this.id, this.type, [this.creationParams]); final int id; final String type; + final Object? creationParams; @override bool operator ==(Object other) { @@ -670,14 +672,15 @@ class FakeHtmlPlatformView { } return other is FakeHtmlPlatformView && other.id == id - && other.type == type; + && other.type == type + && other.creationParams == creationParams; } @override - int get hashCode => Object.hash(id, type); + int get hashCode => Object.hash(id, type, creationParams); @override String toString() { - return 'FakeHtmlPlatformView(id: $id, type: $type)'; + return 'FakeHtmlPlatformView(id: $id, type: $type, params: $creationParams)'; } } diff --git a/packages/flutter/test/widgets/html_element_view_test.dart b/packages/flutter/test/widgets/html_element_view_test.dart index 4b58794dd0..b485aef6c9 100644 --- a/packages/flutter/test/widgets/html_element_view_test.dart +++ b/packages/flutter/test/widgets/html_element_view_test.dart @@ -73,6 +73,42 @@ void main() { ); }); + testWidgets('Create HTML view with creation params', (WidgetTester tester) async { + final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); + final FakeHtmlPlatformViewsController viewsController = FakeHtmlPlatformViewsController(); + viewsController.registerViewType('webview'); + await tester.pumpWidget( + const Column( + children: [ + SizedBox( + width: 200.0, + height: 100.0, + child: HtmlElementView( + viewType: 'webview', + creationParams: 'foobar', + ), + ), + SizedBox( + width: 200.0, + height: 100.0, + child: HtmlElementView( + viewType: 'webview', + creationParams: 123, + ), + ), + ], + ), + ); + + expect( + viewsController.views, + unorderedEquals([ + FakeHtmlPlatformView(currentViewId + 1, 'webview', 'foobar'), + FakeHtmlPlatformView(currentViewId + 2, 'webview', 123), + ]), + ); + }); + testWidgets('Resize HTML view', (WidgetTester tester) async { final int currentViewId = platformViewsRegistry.getNextPlatformViewId(); final FakeHtmlPlatformViewsController viewsController = FakeHtmlPlatformViewsController();