PlatformViewLink, handling creation of the PlatformViewSurface and dispose PlatformViewController (#37703)
* link * review fixes * review fixes * remove extra line
This commit is contained in:
parent
07197e91c3
commit
5acf63d35a
@ -729,4 +729,9 @@ abstract class PlatformViewController {
|
|||||||
|
|
||||||
/// Dispatches the `event` to the platform view.
|
/// Dispatches the `event` to the platform view.
|
||||||
void dispatchPointerEvent(PointerEvent event);
|
void dispatchPointerEvent(PointerEvent event);
|
||||||
|
|
||||||
|
/// Disposes the platform view.
|
||||||
|
///
|
||||||
|
/// The [PlatformViewController] is unusable after calling dispose.
|
||||||
|
void dispose();
|
||||||
}
|
}
|
||||||
|
@ -581,6 +581,136 @@ class _UiKitPlatformView extends LeafRenderObjectWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The parameters used to create a [PlatformViewController].
|
||||||
|
///
|
||||||
|
/// See also [CreatePlatformViewController] which uses this object to create a [PlatformViewController].
|
||||||
|
class PlatformViewCreationParams {
|
||||||
|
|
||||||
|
const PlatformViewCreationParams._({
|
||||||
|
@required this.id,
|
||||||
|
@required this.onPlatformViewCreated
|
||||||
|
}) : assert(id != null),
|
||||||
|
assert(onPlatformViewCreated != null);
|
||||||
|
|
||||||
|
/// The unique identifier for the new platform view.
|
||||||
|
///
|
||||||
|
/// [PlatformViewController.viewId] should match this id.
|
||||||
|
final int id;
|
||||||
|
|
||||||
|
/// Callback invoked after the platform view has been created.
|
||||||
|
final PlatformViewCreatedCallback onPlatformViewCreated;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A factory for a surface presenting a platform view as part of the widget hierarchy.
|
||||||
|
///
|
||||||
|
/// The returned widget should present the platform view associated with `controller`.
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
/// * [PlatformViewSurface], a common widget for presenting platform views.
|
||||||
|
typedef PlatformViewSurfaceFactory = Widget Function(BuildContext context, PlatformViewController controller);
|
||||||
|
|
||||||
|
/// Constructs a [PlatformViewController].
|
||||||
|
///
|
||||||
|
/// The [PlatformViewController.id] field of the created controller must match the value of the
|
||||||
|
/// params [PlatformViewCreationParams.id] field.
|
||||||
|
///
|
||||||
|
/// See also [PlatformViewLink.onCreate].
|
||||||
|
typedef CreatePlatformViewController = PlatformViewController Function(PlatformViewCreationParams params);
|
||||||
|
|
||||||
|
/// Links a platform view with the Flutter framework.
|
||||||
|
///
|
||||||
|
/// Provides common functionality for embedding a platform view (e.g an android.view.View on Android)
|
||||||
|
/// with the Flutter framework.
|
||||||
|
///
|
||||||
|
/// {@macro flutter.widgets.platformViews.lifetime}
|
||||||
|
///
|
||||||
|
/// To implement a new platform view widget, return this widget in the `build` method.
|
||||||
|
/// For example:
|
||||||
|
/// ```dart
|
||||||
|
/// class FooPlatformView extends StatelessWidget {
|
||||||
|
/// @override
|
||||||
|
/// Widget build(BuildContext context) {
|
||||||
|
/// return PlatformViewLink(
|
||||||
|
/// createCallback: createFooWebView,
|
||||||
|
/// surfaceFactory: (BuildContext context, PlatformViewController controller) {
|
||||||
|
/// return PlatformViewSurface(
|
||||||
|
/// gestureRecognizers: gestureRecognizers,
|
||||||
|
/// controller: controller,
|
||||||
|
/// hitTestBehavior: PlatformViewHitTestBehavior.opaque,
|
||||||
|
/// );
|
||||||
|
/// },
|
||||||
|
/// );
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
///
|
||||||
|
/// The `surfaceFactory` and the `createPlatformViewController` only take affect when the state of this widget is initialized.
|
||||||
|
/// If the widget is rebuilt without losing its state, `surfaceFactory` and `createPlatformViewController` are ignored.
|
||||||
|
class PlatformViewLink extends StatefulWidget {
|
||||||
|
|
||||||
|
/// Construct a [PlatformViewLink] widget.
|
||||||
|
///
|
||||||
|
/// The `surfaceFactory` and the `createPlatformViewController` must not be null.
|
||||||
|
///
|
||||||
|
/// See also:
|
||||||
|
/// * [PlatformViewSurface] for details on the widget returned by `surfaceFactory`.
|
||||||
|
/// * [PlatformViewCreationParams] for how each parameter can be used when implementing `createPlatformView`.
|
||||||
|
const PlatformViewLink({
|
||||||
|
Key key,
|
||||||
|
@required PlatformViewSurfaceFactory surfaceFactory,
|
||||||
|
@required CreatePlatformViewController createPlatformViewController,
|
||||||
|
}) : assert(surfaceFactory != null),
|
||||||
|
assert(createPlatformViewController != null),
|
||||||
|
_surfaceFactory = surfaceFactory,
|
||||||
|
_createPlatformViewController = createPlatformViewController,
|
||||||
|
super(key: key);
|
||||||
|
|
||||||
|
|
||||||
|
final PlatformViewSurfaceFactory _surfaceFactory;
|
||||||
|
final CreatePlatformViewController _createPlatformViewController;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<StatefulWidget> createState() => _PlatformViewLinkState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PlatformViewLinkState extends State<PlatformViewLink> {
|
||||||
|
|
||||||
|
int _id;
|
||||||
|
PlatformViewController _controller;
|
||||||
|
bool _platformViewCreated = false;
|
||||||
|
PlatformViewSurface _surface;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
if (!_platformViewCreated) {
|
||||||
|
return const SizedBox.expand();
|
||||||
|
}
|
||||||
|
_surface ??= widget._surfaceFactory(context, _controller);
|
||||||
|
return _surface;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
_initialize();
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void _initialize() {
|
||||||
|
_id = platformViewsRegistry.getNextPlatformViewId();
|
||||||
|
_controller = widget._createPlatformViewController(PlatformViewCreationParams._(id:_id, onPlatformViewCreated:_onPlatformViewCreated));
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onPlatformViewCreated(int id) {
|
||||||
|
setState(() => _platformViewCreated = true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller?.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Integrates a platform view with Flutter's compositor, touch, and semantics subsystems.
|
/// Integrates a platform view with Flutter's compositor, touch, and semantics subsystems.
|
||||||
///
|
///
|
||||||
/// The compositor integration is done by adding a [PlatformViewLayer] to the layer tree. [PlatformViewLayer]
|
/// The compositor integration is done by adding a [PlatformViewLayer] to the layer tree. [PlatformViewLayer]
|
||||||
|
@ -17,6 +17,8 @@ class FakePlatformViewController extends PlatformViewController {
|
|||||||
_id = id;
|
_id = id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool disposed = false;
|
||||||
|
|
||||||
/// Events that are dispatched;
|
/// Events that are dispatched;
|
||||||
List<PointerEvent> dispatchedPointerEvents = <PointerEvent>[];
|
List<PointerEvent> dispatchedPointerEvents = <PointerEvent>[];
|
||||||
|
|
||||||
@ -32,6 +34,12 @@ class FakePlatformViewController extends PlatformViewController {
|
|||||||
|
|
||||||
void clearTestingVariables() {
|
void clearTestingVariables() {
|
||||||
dispatchedPointerEvents.clear();
|
dispatchedPointerEvents.clear();
|
||||||
|
disposed = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
disposed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1932,5 +1932,114 @@ void main() {
|
|||||||
);
|
);
|
||||||
expect(factoryInvocationCount, 1);
|
expect(factoryInvocationCount, 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('PlatformViewLink Widget init, should create a SizedBox widget before onPlatformViewCreated and a PlatformViewSurface after', (WidgetTester tester) async {
|
||||||
|
final int currentViewId = platformViewsRegistry.getNextPlatformViewId();
|
||||||
|
int createdPlatformViewId;
|
||||||
|
|
||||||
|
PlatformViewCreatedCallback onPlatformViewCreatedCallBack;
|
||||||
|
|
||||||
|
final PlatformViewLink platformViewLink = PlatformViewLink(createPlatformViewController: (PlatformViewCreationParams params){
|
||||||
|
onPlatformViewCreatedCallBack = params.onPlatformViewCreated;
|
||||||
|
createdPlatformViewId = params.id;
|
||||||
|
return FakePlatformViewController(params.id);
|
||||||
|
}, surfaceFactory: (BuildContext context, PlatformViewController controller) {
|
||||||
|
return PlatformViewSurface(
|
||||||
|
gestureRecognizers: const <Factory<OneSequenceGestureRecognizer>>{},
|
||||||
|
controller: controller,
|
||||||
|
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
await tester.pumpWidget(platformViewLink);
|
||||||
|
final SizedBox sizedBox = tester.allWidgets.firstWhere((Widget widget) => widget is SizedBox);
|
||||||
|
expect(sizedBox, isNotNull);
|
||||||
|
|
||||||
|
onPlatformViewCreatedCallBack(createdPlatformViewId);
|
||||||
|
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
final PlatformViewSurface surface = tester.allWidgets.firstWhere((Widget widget) => widget is PlatformViewSurface);
|
||||||
|
expect(surface, isNotNull);
|
||||||
|
|
||||||
|
expect(createdPlatformViewId, currentViewId+1);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('PlatformViewLink Widget dispose', (WidgetTester tester) async {
|
||||||
|
FakePlatformViewController disposedController;
|
||||||
|
final PlatformViewLink platformViewLink = PlatformViewLink(createPlatformViewController: (PlatformViewCreationParams params){
|
||||||
|
params.onPlatformViewCreated(params.id);
|
||||||
|
disposedController = FakePlatformViewController(params.id);
|
||||||
|
params.onPlatformViewCreated(params.id);
|
||||||
|
return disposedController;
|
||||||
|
}, surfaceFactory: (BuildContext context,PlatformViewController controller) {
|
||||||
|
return PlatformViewSurface(
|
||||||
|
gestureRecognizers: const <Factory<OneSequenceGestureRecognizer>>{},
|
||||||
|
controller: controller,
|
||||||
|
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
await tester.pumpWidget(platformViewLink);
|
||||||
|
|
||||||
|
await tester.pumpWidget(Container());
|
||||||
|
|
||||||
|
expect(disposedController.disposed, true);
|
||||||
|
});
|
||||||
|
|
||||||
|
testWidgets('PlatformViewLink widget survives widget tree change', (WidgetTester tester) async {
|
||||||
|
final GlobalKey key = GlobalKey();
|
||||||
|
final int currentViewId = platformViewsRegistry.getNextPlatformViewId();
|
||||||
|
final List<int> ids = <int>[];
|
||||||
|
|
||||||
|
FakePlatformViewController controller;
|
||||||
|
|
||||||
|
PlatformViewLink createPlatformViewLink() {
|
||||||
|
return PlatformViewLink(
|
||||||
|
key: key,
|
||||||
|
createPlatformViewController: (PlatformViewCreationParams params){
|
||||||
|
ids.add(params.id);
|
||||||
|
controller = FakePlatformViewController(params.id);
|
||||||
|
params.onPlatformViewCreated(params.id);
|
||||||
|
return controller;
|
||||||
|
},
|
||||||
|
surfaceFactory: (BuildContext context, PlatformViewController controller) {
|
||||||
|
return PlatformViewSurface(
|
||||||
|
gestureRecognizers: const <Factory<OneSequenceGestureRecognizer>>{},
|
||||||
|
controller: controller,
|
||||||
|
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await tester.pumpWidget(
|
||||||
|
Center(
|
||||||
|
child: SizedBox(
|
||||||
|
width: 200.0,
|
||||||
|
height: 100.0,
|
||||||
|
child: createPlatformViewLink(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
await tester.pumpWidget(
|
||||||
|
Center(
|
||||||
|
child: Container(
|
||||||
|
child: SizedBox(
|
||||||
|
width: 200.0,
|
||||||
|
height: 100.0,
|
||||||
|
child: createPlatformViewLink(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
ids,
|
||||||
|
unorderedEquals(<int>[
|
||||||
|
currentViewId+1,
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user