Unverified Commit d1b8527f authored by hellohuanlin's avatar hellohuanlin Committed by GitHub

[platform_view]fix iOS platform view's focus node leakage (#124066)

[platform_view]fix iOS platform view's focus node leakage
parent 85624dd0
......@@ -1378,6 +1378,7 @@ class UiKitViewController {
Future<void> dispose() async {
_debugDisposed = true;
await SystemChannels.platform_views.invokeMethod<void>('dispose', id);
PlatformViewsService._instance._focusCallbacks.remove(id);
}
}
......
......@@ -503,6 +503,8 @@ class _AndroidViewState extends State<AndroidView> {
@override
void dispose() {
_controller.dispose();
_focusNode?.dispose();
_focusNode = null;
super.dispose();
}
......@@ -562,7 +564,9 @@ class _UiKitViewState extends State<UiKitView> {
UiKitViewController? _controller;
TextDirection? _layoutDirection;
bool _initialized = false;
late FocusNode _focusNode;
@visibleForTesting
FocusNode? focusNode;
static final Set<Factory<OneSequenceGestureRecognizer>> _emptyRecognizersSet =
<Factory<OneSequenceGestureRecognizer>>{};
......@@ -574,7 +578,7 @@ class _UiKitViewState extends State<UiKitView> {
return const SizedBox.expand();
}
return Focus(
focusNode: _focusNode,
focusNode: focusNode,
onFocusChange: (bool isFocused) => _onFocusChange(isFocused, controller),
child: _UiKitPlatformView(
controller: _controller!,
......@@ -634,6 +638,9 @@ class _UiKitViewState extends State<UiKitView> {
@override
void dispose() {
_controller?.dispose();
_controller = null;
focusNode?.dispose();
focusNode = null;
super.dispose();
}
......@@ -646,7 +653,7 @@ class _UiKitViewState extends State<UiKitView> {
creationParams: widget.creationParams,
creationParamsCodec: widget.creationParamsCodec,
onFocus: () {
_focusNode.requestFocus();
focusNode?.requestFocus();
}
);
if (!mounted) {
......@@ -656,7 +663,7 @@ class _UiKitViewState extends State<UiKitView> {
widget.onPlatformViewCreated?.call(id);
setState(() {
_controller = controller;
_focusNode = FocusNode(debugLabel: 'UiKitView(id: $id)');
focusNode = FocusNode(debugLabel: 'UiKitView(id: $id)');
});
}
......@@ -938,6 +945,8 @@ class _PlatformViewLinkState extends State<PlatformViewLink> {
void dispose() {
_controller?.dispose();
_controller = null;
_focusNode?.dispose();
_focusNode = null;
super.dispose();
}
}
......
......@@ -2150,6 +2150,34 @@ void main() {
expect(channelArguments['platformViewId'], currentViewId + 1);
});
testWidgets('FocusNode is disposed on UIView dispose', (WidgetTester tester) async {
final FakeIosPlatformViewsController viewsController = FakeIosPlatformViewsController();
viewsController.registerViewType('webview');
await tester.pumpWidget(
const Center(
child: SizedBox(
width: 200.0,
height: 100.0,
child: UiKitView(viewType: 'webview', layoutDirection: TextDirection.ltr),
),
),
);
// casting to dynamic is required since the state class is private.
// ignore: avoid_dynamic_calls, invalid_assignment
final FocusNode node = (tester.state(find.byType(UiKitView)) as dynamic).focusNode;
expect(() => ChangeNotifier.debugAssertNotDisposed(node), isNot(throwsAssertionError));
await tester.pumpWidget(
const Center(
child: SizedBox(
width: 200.0,
height: 100.0,
),
),
);
expect(() => ChangeNotifier.debugAssertNotDisposed(node), throwsAssertionError);
});
testWidgets('UiKitView has correct semantics', (WidgetTester tester) async {
final SemanticsHandle handle = tester.ensureSemantics();
final int currentViewId = platformViewsRegistry.getNextPlatformViewId();
......
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