From 95909c2a04ef62cc72aab61ac26157b8a8ad7a20 Mon Sep 17 00:00:00 2001 From: xubaolin Date: Fri, 23 Oct 2020 06:56:26 +0800 Subject: [PATCH] change TextEditingController.clear() behavior (#68775) Fixes a bug where keyboard capitalization mode was exited when pressing clear. --- .../lib/src/widgets/editable_text.dart | 4 +- .../test/widgets/editable_text_test.dart | 73 +++++++++++++++++++ 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart index fda9b9df6b..c52b54ae75 100644 --- a/packages/flutter/lib/src/widgets/editable_text.dart +++ b/packages/flutter/lib/src/widgets/editable_text.dart @@ -230,14 +230,14 @@ class TextEditingController extends ValueNotifier { /// Set the [value] to empty. /// /// After calling this function, [text] will be the empty string and the - /// selection will be invalid. + /// selection will be collapsed at zero offset. /// /// Calling this will notify all the listeners of this [TextEditingController] /// that they need to update (it calls [notifyListeners]). For this reason, /// this method should only be called between frames, e.g. in response to user /// actions, not during the build, layout, or paint phases. void clear() { - value = TextEditingValue.empty; + value = const TextEditingValue(selection: TextSelection.collapsed(offset: 0)); } /// Set the composing region to an empty range. diff --git a/packages/flutter/test/widgets/editable_text_test.dart b/packages/flutter/test/widgets/editable_text_test.dart index 9c7b2f1314..f7ed48f440 100644 --- a/packages/flutter/test/widgets/editable_text_test.dart +++ b/packages/flutter/test/widgets/editable_text_test.dart @@ -5391,6 +5391,79 @@ void main() { expect(focusNode.hasFocus, false); }); + testWidgets('TextEditingController.clear() behavior test', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/66316 + final List log = []; + SystemChannels.textInput.setMockMethodCallHandler((MethodCall methodCall) async { + log.add(methodCall); + }); + final TextEditingController controller = TextEditingController(); + + final FocusNode focusNode = FocusNode(debugLabel: 'EditableText Focus Node'); + Widget builder() { + return StatefulBuilder( + builder: (BuildContext context, StateSetter setter) { + return MaterialApp( + home: MediaQuery( + data: const MediaQueryData(devicePixelRatio: 1.0), + child: Directionality( + textDirection: TextDirection.ltr, + child: Center( + child: Material( + child: EditableText( + controller: controller, + focusNode: focusNode, + style: textStyle, + cursorColor: Colors.red, + backgroundCursorColor: Colors.red, + keyboardType: TextInputType.multiline, + onChanged: (String value) { }, + ), + ), + ), + ), + ), + ); + }, + ); + } + + await tester.pumpWidget(builder()); + await tester.tap(find.byType(EditableText)); + await tester.pump(); + + // The keyboard is shown after tap the EditableText. + expect(focusNode.hasFocus, true); + + log.clear(); + + final EditableTextState state = tester.firstState(find.byType(EditableText)); + + state.updateEditingValue(const TextEditingValue( + text: 'a', + )); + await tester.pump(); + + // Nothing called when only the remote changes. + expect(log.length, 0); + + controller.clear(); + + expect(log.length, 1); + expect( + log[0], + isMethodCall('TextInput.setEditingState', arguments: { + 'text': '', + 'selectionBase': 0, + 'selectionExtent': 0, + 'selectionAffinity': 'TextAffinity.downstream', + 'selectionIsDirectional': false, + 'composingBase': -1, + 'composingExtent': -1, + }), + ); + }); + testWidgets('autofocus:true on first frame does not throw', (WidgetTester tester) async { final TextEditingController controller = TextEditingController(text: testText); controller.selection = const TextSelection(