[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: <details> <summary>Code sample</summary> ```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, ), ), ); } } ``` </details>  Depends on https://github.com/flutter/engine/pull/42255 Part of https://github.com/flutter/flutter/issues/127030
This commit is contained in:
parent
3246808cd2
commit
b0188cd182
@ -345,6 +345,7 @@ class HtmlElementView extends StatelessWidget {
|
|||||||
super.key,
|
super.key,
|
||||||
required this.viewType,
|
required this.viewType,
|
||||||
this.onPlatformViewCreated,
|
this.onPlatformViewCreated,
|
||||||
|
this.creationParams,
|
||||||
}) : assert(kIsWeb, 'HtmlElementView is only available on Flutter Web.');
|
}) : assert(kIsWeb, 'HtmlElementView is only available on Flutter Web.');
|
||||||
|
|
||||||
/// The unique identifier for the HTML view type to be embedded by this widget.
|
/// 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.
|
/// May be null.
|
||||||
final PlatformViewCreatedCallback? onPlatformViewCreated;
|
final PlatformViewCreatedCallback? onPlatformViewCreated;
|
||||||
|
|
||||||
|
/// Passed as the 2nd argument (i.e. `params`) of the registered view factory.
|
||||||
|
final Object? creationParams;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return PlatformViewLink(
|
return PlatformViewLink(
|
||||||
@ -374,7 +378,11 @@ class HtmlElementView extends StatelessWidget {
|
|||||||
|
|
||||||
/// Creates the controller and kicks off its initialization.
|
/// Creates the controller and kicks off its initialization.
|
||||||
_HtmlElementViewController _createHtmlElementView(PlatformViewCreationParams params) {
|
_HtmlElementViewController _createHtmlElementView(PlatformViewCreationParams params) {
|
||||||
final _HtmlElementViewController controller = _HtmlElementViewController(params.id, viewType);
|
final _HtmlElementViewController controller = _HtmlElementViewController(
|
||||||
|
params.id,
|
||||||
|
viewType,
|
||||||
|
creationParams,
|
||||||
|
);
|
||||||
controller._initialize().then((_) {
|
controller._initialize().then((_) {
|
||||||
params.onPlatformViewCreated(params.id);
|
params.onPlatformViewCreated(params.id);
|
||||||
onPlatformViewCreated?.call(params.id);
|
onPlatformViewCreated?.call(params.id);
|
||||||
@ -387,6 +395,7 @@ class _HtmlElementViewController extends PlatformViewController {
|
|||||||
_HtmlElementViewController(
|
_HtmlElementViewController(
|
||||||
this.viewId,
|
this.viewId,
|
||||||
this.viewType,
|
this.viewType,
|
||||||
|
this.creationParams,
|
||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -397,12 +406,15 @@ class _HtmlElementViewController extends PlatformViewController {
|
|||||||
/// A PlatformViewFactory for this type must have been registered.
|
/// A PlatformViewFactory for this type must have been registered.
|
||||||
final String viewType;
|
final String viewType;
|
||||||
|
|
||||||
|
final dynamic creationParams;
|
||||||
|
|
||||||
bool _initialized = false;
|
bool _initialized = false;
|
||||||
|
|
||||||
Future<void> _initialize() async {
|
Future<void> _initialize() async {
|
||||||
final Map<String, dynamic> args = <String, dynamic>{
|
final Map<String, dynamic> args = <String, dynamic>{
|
||||||
'id': viewId,
|
'id': viewId,
|
||||||
'viewType': viewType,
|
'viewType': viewType,
|
||||||
|
'params': creationParams,
|
||||||
};
|
};
|
||||||
await SystemChannels.platform_views.invokeMethod<void>('create', args);
|
await SystemChannels.platform_views.invokeMethod<void>('create', args);
|
||||||
_initialized = true;
|
_initialized = true;
|
||||||
|
@ -503,6 +503,7 @@ class FakeHtmlPlatformViewsController {
|
|||||||
final Map<dynamic, dynamic> args = call.arguments as Map<dynamic, dynamic>;
|
final Map<dynamic, dynamic> args = call.arguments as Map<dynamic, dynamic>;
|
||||||
final int id = args['id'] as int;
|
final int id = args['id'] as int;
|
||||||
final String viewType = args['viewType'] as String;
|
final String viewType = args['viewType'] as String;
|
||||||
|
final Object? params = args['params'];
|
||||||
|
|
||||||
if (_views.containsKey(id)) {
|
if (_views.containsKey(id)) {
|
||||||
throw PlatformException(
|
throw PlatformException(
|
||||||
@ -522,7 +523,7 @@ class FakeHtmlPlatformViewsController {
|
|||||||
await createCompleter!.future;
|
await createCompleter!.future;
|
||||||
}
|
}
|
||||||
|
|
||||||
_views[id] = FakeHtmlPlatformView(id, viewType);
|
_views[id] = FakeHtmlPlatformView(id, viewType, params);
|
||||||
return Future<int?>.sync(() => null);
|
return Future<int?>.sync(() => null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -658,10 +659,11 @@ class FakeUiKitView {
|
|||||||
|
|
||||||
@immutable
|
@immutable
|
||||||
class FakeHtmlPlatformView {
|
class FakeHtmlPlatformView {
|
||||||
const FakeHtmlPlatformView(this.id, this.type);
|
const FakeHtmlPlatformView(this.id, this.type, [this.creationParams]);
|
||||||
|
|
||||||
final int id;
|
final int id;
|
||||||
final String type;
|
final String type;
|
||||||
|
final Object? creationParams;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) {
|
bool operator ==(Object other) {
|
||||||
@ -670,14 +672,15 @@ class FakeHtmlPlatformView {
|
|||||||
}
|
}
|
||||||
return other is FakeHtmlPlatformView
|
return other is FakeHtmlPlatformView
|
||||||
&& other.id == id
|
&& other.id == id
|
||||||
&& other.type == type;
|
&& other.type == type
|
||||||
|
&& other.creationParams == creationParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get hashCode => Object.hash(id, type);
|
int get hashCode => Object.hash(id, type, creationParams);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() {
|
String toString() {
|
||||||
return 'FakeHtmlPlatformView(id: $id, type: $type)';
|
return 'FakeHtmlPlatformView(id: $id, type: $type, params: $creationParams)';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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: <Widget>[
|
||||||
|
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>[
|
||||||
|
FakeHtmlPlatformView(currentViewId + 1, 'webview', 'foobar'),
|
||||||
|
FakeHtmlPlatformView(currentViewId + 2, 'webview', 123),
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
testWidgets('Resize HTML view', (WidgetTester tester) async {
|
testWidgets('Resize HTML view', (WidgetTester tester) async {
|
||||||
final int currentViewId = platformViewsRegistry.getNextPlatformViewId();
|
final int currentViewId = platformViewsRegistry.getNextPlatformViewId();
|
||||||
final FakeHtmlPlatformViewsController viewsController = FakeHtmlPlatformViewsController();
|
final FakeHtmlPlatformViewsController viewsController = FakeHtmlPlatformViewsController();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user