diff --git a/packages/flutter/lib/src/material/text_field.dart b/packages/flutter/lib/src/material/text_field.dart index 872c9242956..730e31bd2da 100644 --- a/packages/flutter/lib/src/material/text_field.dart +++ b/packages/flutter/lib/src/material/text_field.dart @@ -506,8 +506,8 @@ class _TextFieldState extends State with AutomaticKeepAliveClientMixi return new Semantics( onTap: () { - if (!_controller.selection.isValid) - _controller.selection = new TextSelection.collapsed(offset: _controller.text.length); + if (!_effectiveController.selection.isValid) + _effectiveController.selection = new TextSelection.collapsed(offset: _effectiveController.text.length); _requestKeyboard(); }, child: new IgnorePointer( diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart index ff3f4354126..a8e9cd45a4a 100644 --- a/packages/flutter/test/material/text_field_test.dart +++ b/packages/flutter/test/material/text_field_test.dart @@ -2059,6 +2059,76 @@ void main() { semantics.dispose(); }); + testWidgets('Can activate TextField with explicit controller via semantics ', (WidgetTester tester) async { + // Regression test for https://github.com/flutter/flutter/issues/17801 + + const String textInTextField = 'Hello'; + + final SemanticsTester semantics = new SemanticsTester(tester); + final SemanticsOwner semanticsOwner = tester.binding.pipelineOwner.semanticsOwner; + final TextEditingController controller = new TextEditingController() + ..text = textInTextField; + final Key key = new UniqueKey(); + + await tester.pumpWidget( + overlay( + child: new TextField( + key: key, + controller: controller, + ), + ), + ); + + const int inputFieldId = 1; + + expect(semantics, hasSemantics( + new TestSemantics.root( + children: [ + new TestSemantics( + id: inputFieldId, + flags: [SemanticsFlag.isTextField], + actions: [SemanticsAction.tap], + value: textInTextField, + textDirection: TextDirection.ltr, + ), + ], + ), + ignoreRect: true, ignoreTransform: true, + )); + + semanticsOwner.performAction(inputFieldId, SemanticsAction.tap); + await tester.pump(); + + expect(semantics, hasSemantics( + new TestSemantics.root( + children: [ + new TestSemantics( + id: inputFieldId, + flags: [ + SemanticsFlag.isTextField, + SemanticsFlag.isFocused, + ], + actions: [ + SemanticsAction.tap, + SemanticsAction.moveCursorBackwardByCharacter, + SemanticsAction.setSelection, + SemanticsAction.paste, + ], + value: textInTextField, + textDirection: TextDirection.ltr, + textSelection: const TextSelection( + baseOffset: textInTextField.length, + extentOffset: textInTextField.length, + ), + ), + ], + ), + ignoreRect: true, ignoreTransform: true, + )); + + semantics.dispose(); + }); + testWidgets('TextField throws when not descended from a Material widget', (WidgetTester tester) async { const Widget textField = const TextField(); await tester.pumpWidget(textField);