diff --git a/packages/flutter/lib/src/material/selectable_text.dart b/packages/flutter/lib/src/material/selectable_text.dart index 06eb64e6c18..e1e78f8f3d9 100644 --- a/packages/flutter/lib/src/material/selectable_text.dart +++ b/packages/flutter/lib/src/material/selectable_text.dart @@ -25,7 +25,7 @@ class _TextSpanEditingController extends TextEditingController { _TextSpanEditingController({required TextSpan textSpan}): assert(textSpan != null), _textSpan = textSpan, - super(text: textSpan.toPlainText()); + super(text: textSpan.toPlainText(includeSemanticsLabels: false)); final TextSpan _textSpan; diff --git a/packages/flutter/lib/src/rendering/editable.dart b/packages/flutter/lib/src/rendering/editable.dart index 1cd99663542..510da62ebc9 100644 --- a/packages/flutter/lib/src/rendering/editable.dart +++ b/packages/flutter/lib/src/rendering/editable.dart @@ -1835,7 +1835,7 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin { // Returns the obscured text when [obscureText] is true. See // [obscureText] and [obscuringCharacter]. String get _plainText { - _cachedPlainText ??= _textPainter.text!.toPlainText(); + _cachedPlainText ??= _textPainter.text!.toPlainText(includeSemanticsLabels: false); return _cachedPlainText!; } @@ -2993,8 +2993,7 @@ class RenderEditable extends RenderBox with RelayoutWhenSystemFontsChangeMixin { return TextSelection(baseOffset: 0, extentOffset: _plainText.length); // If the word is a space, on iOS try to select the previous word instead. // On Android try to select the previous word instead only if the text is read only. - } else if (text?.toPlainText() != null - && _isWhitespace(text!.toPlainText().codeUnitAt(position.offset)) + } else if (_isWhitespace(_plainText.codeUnitAt(position.offset)) && position.offset > 0) { assert(defaultTargetPlatform != null); final TextRange? previousWord = _getPreviousWord(word.start); diff --git a/packages/flutter/test/widgets/selectable_text_test.dart b/packages/flutter/test/widgets/selectable_text_test.dart index 0561cac392c..2deef600e20 100644 --- a/packages/flutter/test/widgets/selectable_text_test.dart +++ b/packages/flutter/test/widgets/selectable_text_test.dart @@ -2866,6 +2866,37 @@ void main() { expect(find.byType(CupertinoButton), findsNWidgets(1)); }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + testWidgets( + 'double tap selects word with semantics label', + (WidgetTester tester) async { + await tester.pumpWidget( + const MaterialApp( + home: Material( + child: Center( + child: SelectableText.rich( + TextSpan(text: 'Atwater Peel Sherbrooke Bonaventure', semanticsLabel: ''), + ), + ), + ), + ), + ); + + final Offset selectableTextStart = tester.getTopLeft(find.byType(SelectableText)); + + await tester.tapAt(selectableTextStart + const Offset(220.0, 5.0)); + await tester.pump(const Duration(milliseconds: 50)); + await tester.tapAt(selectableTextStart + const Offset(220.0, 5.0)); + await tester.pump(); + + final EditableText editableTextWidget = tester.widget(find.byType(EditableText).first); + final TextEditingController controller = editableTextWidget.controller; + + expect( + controller.selection, + const TextSelection(baseOffset: 13, extentOffset: 23), + ); + }, variant: const TargetPlatformVariant({ TargetPlatform.iOS, TargetPlatform.macOS })); + testWidgets( 'tap after a double tap select is not affected (iOS)', (WidgetTester tester) async {