Unverified Commit 5acf63d3 authored by Chris Yang's avatar Chris Yang Committed by GitHub

PlatformViewLink, handling creation of the PlatformViewSurface and dispose...

PlatformViewLink, handling creation of the PlatformViewSurface and dispose PlatformViewController (#37703)

* link

* review fixes

* review fixes

* remove extra line
parent 07197e91
...@@ -729,4 +729,9 @@ abstract class PlatformViewController { ...@@ -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 { ...@@ -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 { ...@@ -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 { ...@@ -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() { ...@@ -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,
]),
);
});
}); });
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment