Skip to content

Commit 203ef6f

Browse files
yaakovschectmanloic-sharmagoderbauercbracken
authored
Extract common functionality of iOS platformviews into superclasses (#128716)
Move most functionality of `UiKitView` and its supporting classes into superclasses named `DarwinPlatformView`, etc., and create trivial or near-trivial subclasses with the same names as the old classes. I am currently awaiting approval for a macOS workstation that would allow me to run the iOS/macOS tests and make sure all existing functionality is preserved by this refactor. I can ensure that tests will pass, but doing so may need to wait for a while. Addresses [Add AppKitView](flutter/flutter#128519) ## Pre-launch Checklist - [x] I read the [Contributor Guide] and followed the process outlined there for submitting PRs. - [x] I read the [Tree Hygiene] wiki page, which explains my responsibilities. - [x] I read and followed the [Flutter Style Guide], including [Features we expect every widget to implement]. - [ ] I signed the [CLA]. - [x] I listed at least one issue that this PR fixes in the description above. - [x] I updated/added relevant documentation (doc comments with `///`). - [ ] I added new tests to check the change I am making, or this PR is [test-exempt]. - [x] All existing and new tests are passing. If you need help, consider asking for advice on the #hackers-new channel on [Discord]. <!-- Links --> [Contributor Guide]: https://github.com/flutter/flutter/wiki/Tree-hygiene#overview [Tree Hygiene]: https://github.com/flutter/flutter/wiki/Tree-hygiene [test-exempt]: https://github.com/flutter/flutter/wiki/Tree-hygiene#tests [Flutter Style Guide]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo [Features we expect every widget to implement]: https://github.com/flutter/flutter/wiki/Style-guide-for-Flutter-repo#features-we-expect-every-widget-to-implement [CLA]: https://cla.developers.google.com/ [flutter/tests]: https://github.com/flutter/tests [breaking change policy]: https://github.com/flutter/flutter/wiki/Tree-hygiene#handling-breaking-changes [Discord]: https://github.com/flutter/flutter/wiki/Chat --------- Co-authored-by: Loïc Sharma <737941+loic-sharma@users.noreply.github.com> Co-authored-by: Michael Goderbauer <goderbauer@google.com> Co-authored-by: Chris Bracken <chris@bracken.jp>
1 parent beb245c commit 203ef6f

3 files changed

Lines changed: 188 additions & 105 deletions

File tree

packages/flutter/lib/src/rendering/platform_view.dart

Lines changed: 76 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -269,41 +269,23 @@ class RenderAndroidView extends PlatformViewRenderBox {
269269
}
270270
}
271271

272-
/// A render object for an iOS UIKit UIView.
273-
///
274-
/// [RenderUiKitView] is responsible for sizing and displaying an iOS
275-
/// [UIView](https://developer.apple.com/documentation/uikit/uiview).
276-
///
277-
/// UIViews are added as sub views of the FlutterView and are composited by Quartz.
278-
///
279-
/// {@macro flutter.rendering.RenderAndroidView.layout}
280-
///
281-
/// {@macro flutter.rendering.RenderAndroidView.gestures}
272+
/// Common render-layer functionality for iOS and macOS platform views.
282273
///
283-
/// See also:
284-
///
285-
/// * [UiKitView] which is a widget that is used to show a UIView.
286-
/// * [PlatformViewsService] which is a service for controlling platform views.
287-
class RenderUiKitView extends RenderBox {
288-
/// Creates a render object for an iOS UIView.
289-
///
290-
/// The `viewId`, `hitTestBehavior`, and `gestureRecognizers` parameters must not be null.
291-
RenderUiKitView({
292-
required UiKitViewController viewController,
274+
/// Provides the basic rendering logic for iOS and macOS platformviews.
275+
/// Subclasses shall override handleEvent in order to execute custom event logic.
276+
/// T represents the class of the view controller for the corresponding widget.
277+
abstract class RenderDarwinPlatformView<T extends DarwinPlatformViewController> extends RenderBox {
278+
/// Creates a render object for a platform view.
279+
RenderDarwinPlatformView({
280+
required T viewController,
293281
required this.hitTestBehavior,
294-
required Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers,
295-
}) : _viewController = viewController {
296-
updateGestureRecognizers(gestureRecognizers);
297-
}
282+
}) : _viewController = viewController;
298283

299284

300-
/// The unique identifier of the UIView controlled by this controller.
301-
///
302-
/// Typically generated by [PlatformViewsRegistry.getNextPlatformViewId], the UIView
303-
/// must have been created by calling [PlatformViewsService.initUiKitView].
304-
UiKitViewController get viewController => _viewController;
305-
UiKitViewController _viewController;
306-
set viewController(UiKitViewController value) {
285+
/// The unique identifier of the platform view controlled by this controller.
286+
T get viewController => _viewController;
287+
T _viewController;
288+
set viewController(T value) {
307289
if (_viewController == value) {
308290
return;
309291
}
@@ -320,20 +302,6 @@ class RenderUiKitView extends RenderBox {
320302
// any newly arriving events there's nothing we need to invalidate.
321303
PlatformViewHitTestBehavior hitTestBehavior;
322304

323-
/// {@macro flutter.rendering.PlatformViewRenderBox.updateGestureRecognizers}
324-
void updateGestureRecognizers(Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers) {
325-
assert(
326-
_factoriesTypeSet(gestureRecognizers).length == gestureRecognizers.length,
327-
'There were multiple gesture recognizer factories for the same type, there must only be a single '
328-
'gesture recognizer factory for each gesture recognizer type.',
329-
);
330-
if (_factoryTypesSetEquals(gestureRecognizers, _gestureRecognizer?.gestureRecognizerFactories)) {
331-
return;
332-
}
333-
_gestureRecognizer?.dispose();
334-
_gestureRecognizer = _UiKitViewGestureRecognizer(viewController, gestureRecognizers);
335-
}
336-
337305
@override
338306
bool get sizedByParent => true;
339307

@@ -343,8 +311,6 @@ class RenderUiKitView extends RenderBox {
343311
@override
344312
bool get isRepaintBoundary => true;
345313

346-
_UiKitViewGestureRecognizer? _gestureRecognizer;
347-
348314
PointerEvent? _lastPointerDownEvent;
349315

350316
@override
@@ -372,15 +338,6 @@ class RenderUiKitView extends RenderBox {
372338
@override
373339
bool hitTestSelf(Offset position) => hitTestBehavior != PlatformViewHitTestBehavior.transparent;
374340

375-
@override
376-
void handleEvent(PointerEvent event, HitTestEntry entry) {
377-
if (event is! PointerDownEvent) {
378-
return;
379-
}
380-
_gestureRecognizer!.addPointer(event);
381-
_lastPointerDownEvent = event.original ?? event;
382-
}
383-
384341
// This is registered as a global PointerRoute while the render object is attached.
385342
void _handleGlobalPointerEvent(PointerEvent event) {
386343
if (event is! PointerDownEvent) {
@@ -415,6 +372,69 @@ class RenderUiKitView extends RenderBox {
415372
@override
416373
void detach() {
417374
GestureBinding.instance.pointerRouter.removeGlobalRoute(_handleGlobalPointerEvent);
375+
super.detach();
376+
}
377+
}
378+
379+
/// A render object for an iOS UIKit UIView.
380+
///
381+
/// [RenderUiKitView] is responsible for sizing and displaying an iOS
382+
/// [UIView](https://developer.apple.com/documentation/uikit/uiview).
383+
///
384+
/// UIViews are added as subviews of the FlutterView and are composited by Quartz.
385+
///
386+
/// The viewController is typically generated by [PlatformViewsRegistry.getNextPlatformViewId], the UIView
387+
/// must have been created by calling [PlatformViewsService.initUiKitView].
388+
///
389+
/// {@macro flutter.rendering.RenderAndroidView.layout}
390+
///
391+
/// {@macro flutter.rendering.RenderAndroidView.gestures}
392+
///
393+
/// See also:
394+
///
395+
/// * [UiKitView], which is a widget that is used to show a UIView.
396+
/// * [PlatformViewsService], which is a service for controlling platform views.
397+
class RenderUiKitView extends RenderDarwinPlatformView<UiKitViewController> {
398+
/// Creates a render object for an iOS UIView.
399+
///
400+
/// The `viewId`, `hitTestBehavior`, and `gestureRecognizers` parameters must not be null.
401+
RenderUiKitView({
402+
required super.viewController,
403+
required super.hitTestBehavior,
404+
required Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers
405+
}) {
406+
updateGestureRecognizers(gestureRecognizers);
407+
}
408+
409+
// TODO(schectman): Add gesture functionality to macOS platform view when implemented.
410+
// https://github.com/flutter/flutter/issues/128519
411+
/// {@macro flutter.rendering.PlatformViewRenderBox.updateGestureRecognizers}
412+
void updateGestureRecognizers(Set<Factory<OneSequenceGestureRecognizer>> gestureRecognizers) {
413+
assert(
414+
_factoriesTypeSet(gestureRecognizers).length == gestureRecognizers.length,
415+
'There were multiple gesture recognizer factories for the same type, there must only be a single '
416+
'gesture recognizer factory for each gesture recognizer type.',
417+
);
418+
if (_factoryTypesSetEquals(gestureRecognizers, _gestureRecognizer?.gestureRecognizerFactories)) {
419+
return;
420+
}
421+
_gestureRecognizer?.dispose();
422+
_gestureRecognizer = _UiKitViewGestureRecognizer(viewController, gestureRecognizers);
423+
}
424+
425+
@override
426+
void handleEvent(PointerEvent event, HitTestEntry entry) {
427+
if (event is! PointerDownEvent) {
428+
return;
429+
}
430+
_gestureRecognizer!.addPointer(event);
431+
_lastPointerDownEvent = event.original ?? event;
432+
}
433+
434+
_UiKitViewGestureRecognizer? _gestureRecognizer;
435+
436+
@override
437+
void detach() {
418438
_gestureRecognizer!.reset();
419439
super.detach();
420440
}

packages/flutter/lib/src/services/platform_views.dart

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1313,11 +1313,13 @@ class _HybridAndroidViewControllerInternals extends _AndroidViewControllerIntern
13131313
}
13141314
}
13151315

1316-
/// Controls an iOS UIView.
1316+
/// Base class for iOS and macOS view controllers.
13171317
///
1318-
/// Typically created with [PlatformViewsService.initUiKitView].
1319-
class UiKitViewController {
1320-
UiKitViewController._(
1318+
/// View controllers are used to create and interact with the UIView or NSView
1319+
/// underlying a platform view.
1320+
abstract class DarwinPlatformViewController {
1321+
/// Public default for subclasses to override.
1322+
DarwinPlatformViewController(
13211323
this.id,
13221324
TextDirection layoutDirection,
13231325
) : _layoutDirection = layoutDirection;
@@ -1382,6 +1384,18 @@ class UiKitViewController {
13821384
}
13831385
}
13841386

1387+
/// Controller for an iOS platform view.
1388+
///
1389+
/// View controllers create and interact with the underlying UIView.
1390+
///
1391+
/// Typically created with [PlatformViewsService.initUiKitView].
1392+
class UiKitViewController extends DarwinPlatformViewController {
1393+
UiKitViewController._(
1394+
super.id,
1395+
super.layoutDirection,
1396+
);
1397+
}
1398+
13851399
/// An interface for controlling a single platform view.
13861400
///
13871401
/// Used by [PlatformViewSurface] to interface with the platform view it embeds.

0 commit comments

Comments
 (0)