Prevent the keyboard from reshowing on iOS (#154584)

Fixes https://github.com/flutter/flutter/issues/154156

Some iOS keyboard implementations change the selection in the text field if dismissed with active composing regions. The framework should not call `requestKeyboard` in such cases since that would bring up the keyboard again. 
In general the `TextInput.show` call is not needed for selection only changes. For working around https://github.com/flutter/flutter/issues/68571 the show call is needed only if we restarted the input on Android (and we don't restart on selection-only changes any way).
This commit is contained in:
LongCatIsLooong 2024-09-12 14:29:13 -07:00 committed by GitHub
parent ea3c3e719e
commit dbb588b6e8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 32 additions and 12 deletions

View file

@ -3975,9 +3975,6 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
case SelectionChangedCause.toolbar:
requestKeyboard();
case SelectionChangedCause.keyboard:
if (_hasFocus) {
requestKeyboard();
}
}
if (widget.selectionControls == null && widget.contextMenuBuilder == null) {
_selectionOverlay?.dispose();

View file

@ -3882,6 +3882,37 @@ void main() {
])));
});
testWidgets(
'does not request keyboard after the keyboard changes the selection',
(WidgetTester tester) async {
// Regression test for https://github.com/flutter/flutter/issues/154156.
final Widget widget = MaterialApp(
home: EditableText(
backgroundCursorColor: Colors.grey,
style: Typography.material2018().black.titleMedium!,
cursorColor: Colors.blue,
focusNode: focusNode,
controller: controller,
),
);
controller.value = const TextEditingValue(text: '123', selection: TextSelection.collapsed(offset: 0));
await tester.pumpWidget(widget);
focusNode.requestFocus();
await tester.pump();
assert(focusNode.hasFocus);
tester.testTextInput.log.clear();
final EditableTextState state = tester.state<EditableTextState>(find.byType(EditableText));
state.userUpdateTextEditingValue(const TextEditingValue(text: '123', selection: TextSelection.collapsed(offset: 1)), SelectionChangedCause.keyboard);
expect(
tester.testTextInput.log.map((MethodCall m) => m.method),
isNot(contains('TextInput.show')),
);
});
testWidgets(
'iOS autocorrection rectangle should appear on demand and dismiss when the text changes or when focus is lost',
(WidgetTester tester) async {
@ -10396,14 +10427,8 @@ void main() {
'TextInput.setEditingState',
'TextInput.show',
'TextInput.setCaretRect',
'TextInput.show',
];
expect(tester.testTextInput.log.length, logOrder.length);
int index = 0;
for (final MethodCall m in tester.testTextInput.log) {
expect(m.method, logOrder[index]);
index++;
}
expect(tester.testTextInput.log.map((MethodCall m) => m.method), logOrder);
expect(tester.testTextInput.editingState!['text'], 'flutter is the best!');
});
@ -10638,7 +10663,6 @@ void main() {
// setEditingState is called when remote value modified by the formatter.
state.updateEditingValue(collapsedAtEnd('I will be modified by the formatter.'));
expect(log.length, 2);
expect(log, contains(matchesMethodCall(
'TextInput.setEditingState',
args: allOf(
@ -10649,7 +10673,6 @@ void main() {
log.clear();
state.updateEditingValue(collapsedAtEnd('I will be modified by the formatter.'));
expect(log.length, 2);
expect(log, contains(matchesMethodCall(
'TextInput.setEditingState',
args: allOf(