Allow Flutter focus to interop with Android view hierarchies (#84055)
This commit is contained in:
parent
17b024a584
commit
734df6f5c6
@ -537,7 +537,7 @@ class _AndroidViewState extends State<AndroidView> {
|
|||||||
}
|
}
|
||||||
SystemChannels.textInput.invokeMethod<void>(
|
SystemChannels.textInput.invokeMethod<void>(
|
||||||
'TextInput.setPlatformViewClient',
|
'TextInput.setPlatformViewClient',
|
||||||
_id,
|
<String, dynamic>{'platformViewId': _id, 'usesVirtualDisplay': true},
|
||||||
).catchError((dynamic e) {
|
).catchError((dynamic e) {
|
||||||
if (e is MissingPluginException) {
|
if (e is MissingPluginException) {
|
||||||
// We land the framework part of Android platform views keyboard
|
// We land the framework part of Android platform views keyboard
|
||||||
@ -893,6 +893,10 @@ class _PlatformViewLinkState extends State<PlatformViewLink> {
|
|||||||
if (!isFocused) {
|
if (!isFocused) {
|
||||||
_controller?.clearFocus();
|
_controller?.clearFocus();
|
||||||
}
|
}
|
||||||
|
SystemChannels.textInput.invokeMethod<void>(
|
||||||
|
'TextInput.setPlatformViewClient',
|
||||||
|
<String, dynamic>{'platformViewId': _id},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handlePlatformFocusChanged(bool isFocused){
|
void _handlePlatformFocusChanged(bool isFocused){
|
||||||
|
@ -1074,10 +1074,10 @@ void main() {
|
|||||||
containerFocusNode.requestFocus();
|
containerFocusNode.requestFocus();
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
|
|
||||||
late int lastPlatformViewTextClient;
|
late Map<String, dynamic> lastPlatformViewTextClient;
|
||||||
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall call) {
|
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall call) {
|
||||||
if (call.method == 'TextInput.setPlatformViewClient') {
|
if (call.method == 'TextInput.setPlatformViewClient') {
|
||||||
lastPlatformViewTextClient = call.arguments as int;
|
lastPlatformViewTextClient = call.arguments as Map<String, dynamic>;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
@ -1085,7 +1085,11 @@ void main() {
|
|||||||
viewsController.invokeViewFocused(currentViewId + 1);
|
viewsController.invokeViewFocused(currentViewId + 1);
|
||||||
await tester.pump();
|
await tester.pump();
|
||||||
|
|
||||||
expect(lastPlatformViewTextClient, currentViewId + 1);
|
expect(lastPlatformViewTextClient.containsKey('platformViewId'), true);
|
||||||
|
expect(lastPlatformViewTextClient['platformViewId'], currentViewId + 1);
|
||||||
|
|
||||||
|
expect(lastPlatformViewTextClient.containsKey('usesVirtualDisplay'), true);
|
||||||
|
expect(lastPlatformViewTextClient['usesVirtualDisplay'], true);
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('AndroidView clears platform focus when unfocused', (WidgetTester tester) async {
|
testWidgets('AndroidView clears platform focus when unfocused', (WidgetTester tester) async {
|
||||||
@ -2560,6 +2564,57 @@ void main() {
|
|||||||
expect(platformViewFocusNode.hasFocus, false);
|
expect(platformViewFocusNode.hasFocus, false);
|
||||||
expect(controller.focusCleared, true);
|
expect(controller.focusCleared, true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
testWidgets('PlatformViewLink sets a platform view text input client when focused', (WidgetTester tester) async {
|
||||||
|
late FakePlatformViewController controller;
|
||||||
|
late int viewId;
|
||||||
|
|
||||||
|
final PlatformViewLink platformViewLink = PlatformViewLink(
|
||||||
|
viewType: 'test',
|
||||||
|
onCreatePlatformView: (PlatformViewCreationParams params) {
|
||||||
|
viewId = params.id;
|
||||||
|
params.onPlatformViewCreated(params.id);
|
||||||
|
controller = FakePlatformViewController(params.id);
|
||||||
|
return controller;
|
||||||
|
},
|
||||||
|
surfaceFactory: (BuildContext context, PlatformViewController controller) {
|
||||||
|
return PlatformViewSurface(
|
||||||
|
gestureRecognizers: const <Factory<OneSequenceGestureRecognizer>>{},
|
||||||
|
controller: controller,
|
||||||
|
hitTestBehavior: PlatformViewHitTestBehavior.opaque,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
await tester.pumpWidget(SizedBox(width: 300, height: 300, child: platformViewLink));
|
||||||
|
|
||||||
|
final Focus platformViewFocusWidget = tester.widget(
|
||||||
|
find.descendant(
|
||||||
|
of: find.byType(PlatformViewLink),
|
||||||
|
matching: find.byType(Focus),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final FocusNode? focusNode = platformViewFocusWidget.focusNode;
|
||||||
|
expect(focusNode, isNotNull);
|
||||||
|
expect(focusNode!.hasFocus, false);
|
||||||
|
|
||||||
|
late Map<String, dynamic> lastPlatformViewTextClient;
|
||||||
|
tester.binding.defaultBinaryMessenger.setMockMethodCallHandler(SystemChannels.textInput, (MethodCall call) {
|
||||||
|
if (call.method == 'TextInput.setPlatformViewClient') {
|
||||||
|
lastPlatformViewTextClient = call.arguments as Map<String, dynamic>;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
});
|
||||||
|
|
||||||
|
platformViewFocusWidget.focusNode!.requestFocus();
|
||||||
|
await tester.pump();
|
||||||
|
|
||||||
|
expect(focusNode.hasFocus, true);
|
||||||
|
expect(lastPlatformViewTextClient.containsKey('platformViewId'), true);
|
||||||
|
expect(lastPlatformViewTextClient['platformViewId'], viewId);
|
||||||
|
|
||||||
|
expect(lastPlatformViewTextClient.containsKey('usesVirtualDisplay'), false);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
testWidgets('Platform views respect hitTestBehavior', (WidgetTester tester) async {
|
testWidgets('Platform views respect hitTestBehavior', (WidgetTester tester) async {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user