Keep the selection after 'Copy' pressed on iOS. (#76327)
diff --git a/packages/flutter/lib/src/cupertino/text_selection.dart b/packages/flutter/lib/src/cupertino/text_selection.dart
index f41dcb9..56b0cdd 100644
--- a/packages/flutter/lib/src/cupertino/text_selection.dart
+++ b/packages/flutter/lib/src/cupertino/text_selection.dart
@@ -6,6 +6,7 @@
import 'package:flutter/widgets.dart';
import 'package:flutter/rendering.dart';
+import 'package:flutter/services.dart';
import 'localizations.dart';
import 'text_selection_toolbar.dart';
diff --git a/packages/flutter/lib/src/services/text_input.dart b/packages/flutter/lib/src/services/text_input.dart
index 7b7fd3e..c778a10 100644
--- a/packages/flutter/lib/src/services/text_input.dart
+++ b/packages/flutter/lib/src/services/text_input.dart
@@ -774,7 +774,11 @@
set textEditingValue(TextEditingValue value);
/// Hides the text selection toolbar.
- void hideToolbar();
+ ///
+ /// By default, hideHandles is true, and the toolbar is hidden along with its
+ /// handles. If hideHandles is set to false, then the toolbar will be hidden
+ /// but the handles will remain.
+ void hideToolbar([bool hideHandles = true]);
/// Brings the provided [TextPosition] into the visible area of the text
/// input.
diff --git a/packages/flutter/lib/src/widgets/editable_text.dart b/packages/flutter/lib/src/widgets/editable_text.dart
index 4515a79..3c6eb54 100644
--- a/packages/flutter/lib/src/widgets/editable_text.dart
+++ b/packages/flutter/lib/src/widgets/editable_text.dart
@@ -2505,8 +2505,14 @@
}
@override
- void hideToolbar() {
- _selectionOverlay?.hide();
+ void hideToolbar([bool hideHandles = true]) {
+ if (hideHandles) {
+ // Hide the handles and the toolbar.
+ _selectionOverlay?.hide();
+ } else {
+ // Hide only the toolbar but not the handles.
+ _selectionOverlay?.hideToolbar();
+ }
}
/// Toggles the visibility of the toolbar.
diff --git a/packages/flutter/lib/src/widgets/text_selection.dart b/packages/flutter/lib/src/widgets/text_selection.dart
index 40c6887..7f83b49 100644
--- a/packages/flutter/lib/src/widgets/text_selection.dart
+++ b/packages/flutter/lib/src/widgets/text_selection.dart
@@ -228,12 +228,26 @@
text: value.selection.textInside(value.text),
));
clipboardStatus?.update();
- delegate.textEditingValue = TextEditingValue(
- text: value.text,
- selection: TextSelection.collapsed(offset: value.selection.end),
- );
delegate.bringIntoView(delegate.textEditingValue.selection.extent);
- delegate.hideToolbar();
+
+ switch (defaultTargetPlatform) {
+ case TargetPlatform.iOS:
+ // Hide the toolbar, but keep the selection and keep the handles.
+ delegate.hideToolbar(false);
+ return;
+ case TargetPlatform.macOS:
+ case TargetPlatform.android:
+ case TargetPlatform.fuchsia:
+ case TargetPlatform.linux:
+ case TargetPlatform.windows:
+ // Collapse the selection and hide the toolbar and handles.
+ delegate.textEditingValue = TextEditingValue(
+ text: value.text,
+ selection: TextSelection.collapsed(offset: value.selection.end),
+ );
+ delegate.hideToolbar();
+ return;
+ }
}
/// Paste the current clipboard selection (obtained from [Clipboard]) into
diff --git a/packages/flutter/test/cupertino/text_selection_test.dart b/packages/flutter/test/cupertino/text_selection_test.dart
index 9b259d4..4294a11 100644
--- a/packages/flutter/test/cupertino/text_selection_test.dart
+++ b/packages/flutter/test/cupertino/text_selection_test.dart
@@ -197,17 +197,34 @@
await tester.pump(const Duration(milliseconds: 50));
await tester.tapAt(textOffsetToPosition(tester, index));
await tester.pumpAndSettle();
+ expect(controller.selection.isCollapsed, isFalse);
+ expect(controller.selection.baseOffset, 0);
+ expect(controller.selection.extentOffset, 7);
// Paste is showing even though clipboard is empty.
expect(find.text('Paste'), findsOneWidget);
expect(find.text('Copy'), findsOneWidget);
expect(find.text('Cut'), findsOneWidget);
+ expect(find.descendant(
+ of: find.byType(Overlay),
+ matching: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_TextSelectionHandleOverlay'),
+ ), findsNWidgets(2));
// Tap copy to add something to the clipboard and close the menu.
await tester.tapAt(tester.getCenter(find.text('Copy')));
await tester.pumpAndSettle();
+
+ // The menu is gone, but the handles are visible on the existing selection.
expect(find.text('Copy'), findsNothing);
expect(find.text('Cut'), findsNothing);
+ expect(find.text('Paste'), findsNothing);
+ expect(controller.selection.isCollapsed, isFalse);
+ expect(controller.selection.baseOffset, 0);
+ expect(controller.selection.extentOffset, 7);
+ expect(find.descendant(
+ of: find.byType(Overlay),
+ matching: find.byWidgetPredicate((Widget w) => '${w.runtimeType}' == '_TextSelectionHandleOverlay'),
+ ), findsNWidgets(2));
// Double tap to show the menu again.
await tester.tapAt(textOffsetToPosition(tester, index));
diff --git a/packages/flutter/test/rendering/editable_test.dart b/packages/flutter/test/rendering/editable_test.dart
index 812410f..d6912b2 100644
--- a/packages/flutter/test/rendering/editable_test.dart
+++ b/packages/flutter/test/rendering/editable_test.dart
@@ -19,7 +19,7 @@
TextEditingValue textEditingValue = TextEditingValue.empty;
@override
- void hideToolbar() { }
+ void hideToolbar([bool hideHandles = true]) { }
@override
void bringIntoView(TextPosition position) { }