Unverified Commit ff53fbe1 authored by Justin McCandless's avatar Justin McCandless Committed by GitHub

Text selection menu show/hide cases (#35219)

Show and hide the text selection menu at the correct time with various gestures in the text field.
parent ef42c36a
......@@ -762,6 +762,7 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
}
void _handleSingleTapUp(TapUpDetails details) {
_editableTextKey.currentState.hideToolbar();
if (widget.selectionEnabled) {
switch (Theme.of(context).platform) {
case TargetPlatform.iOS:
......
......@@ -1447,7 +1447,7 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
_showCaretOnScreen();
if (!_value.selection.isValid) {
// Place cursor at the end if the selection is invalid when we receive focus.
widget.controller.selection = TextSelection.collapsed(offset: _value.text.length);
_handleSelectionChanged(TextSelection.collapsed(offset: _value.text.length), renderEditable, null);
}
} else {
WidgetsBinding.instance.removeObserver(this);
......@@ -1500,6 +1500,9 @@ class EditableTextState extends State<EditableText> with AutomaticKeepAliveClien
@override
void hideToolbar() {
if (_selectionOverlay == null || !_selectionOverlay.toolbarIsVisible) {
return;
}
_selectionOverlay?.hide();
}
......
......@@ -3650,5 +3650,31 @@ void main() {
expect(tester.getTopLeft(find.byType(EditableText)).dy, closeTo(329.0, .0001));
});
});
testWidgets(
'Long press on an autofocused field shows the selection menu',
(WidgetTester tester) async {
await tester.pumpWidget(
CupertinoApp(
home: Center(
child: ConstrainedBox(
constraints: BoxConstraints.loose(const Size(200, 200)),
child: const CupertinoTextField(
autofocus: true,
),
),
),
),
);
// This extra pump allows the selection set by autofocus to propagate to
// the RenderEditable.
await tester.pump();
// Long press shows the selection menu.
await tester.longPressAt(textOffsetToPosition(tester, 0));
await tester.pump();
expect(find.text('Paste'), findsOneWidget);
},
);
});
}
......@@ -92,19 +92,21 @@ Widget overlayWithEntry(OverlayEntry entry) {
}
Widget boilerplate({ Widget child }) {
return Localizations(
locale: const Locale('en', 'US'),
delegates: <LocalizationsDelegate<dynamic>>[
WidgetsLocalizationsDelegate(),
MaterialLocalizationsDelegate(),
],
child: Directionality(
textDirection: TextDirection.ltr,
child: MediaQuery(
data: const MediaQueryData(size: Size(800.0, 600.0)),
child: Center(
child: Material(
child: child,
return MaterialApp(
home: Localizations(
locale: const Locale('en', 'US'),
delegates: <LocalizationsDelegate<dynamic>>[
WidgetsLocalizationsDelegate(),
MaterialLocalizationsDelegate(),
],
child: Directionality(
textDirection: TextDirection.ltr,
child: MediaQuery(
data: const MediaQueryData(size: Size(800.0, 600.0)),
child: Center(
child: Material(
child: child,
),
),
),
),
......@@ -5341,6 +5343,66 @@ void main() {
},
);
testWidgets(
'A single tap hides the selection menu',
(WidgetTester tester) async {
final TextEditingController controller = TextEditingController(
text: '',
);
await tester.pumpWidget(
MaterialApp(
home: Material(
child: Center(
child: TextField(
controller: controller,
),
),
),
),
);
// Long press shows the selection menu.
await tester.longPress(find.byType(TextField));
await tester.pump();
expect(find.text('PASTE'), findsOneWidget);
// Tap hides the selection menu.
await tester.tap(find.byType(TextField));
await tester.pump();
expect(find.text('PASTE'), findsNothing);
},
);
testWidgets(
'Long press on an autofocused field shows the selection menu',
(WidgetTester tester) async {
final TextEditingController controller = TextEditingController(
text: '',
);
await tester.pumpWidget(
MaterialApp(
home: Material(
child: Center(
child: TextField(
autofocus: true,
controller: controller,
),
),
),
),
);
// This extra pump allows the selection set by autofocus to propagate to
// the RenderEditable.
await tester.pump();
// Long press shows the selection menu.
expect(find.text('PASTE'), findsNothing);
await tester.longPress(find.byType(TextField));
await tester.pump();
expect(find.text('PASTE'), findsOneWidget);
},
);
testWidgets(
'double tap hold selects word (iOS)',
(WidgetTester tester) async {
......
......@@ -202,27 +202,29 @@ void main() {
final PageController pageController = PageController(initialPage: 1);
await tester.pumpWidget(
MediaQuery(
data: const MediaQueryData(devicePixelRatio: 1.0),
child: Directionality(
textDirection: TextDirection.ltr,
child: Material(
child: PageView(
controller: pageController,
children: <Widget>[
Container(
color: Colors.red,
),
Container(
child: TextField(
controller: textController,
MaterialApp(
home: MediaQuery(
data: const MediaQueryData(devicePixelRatio: 1.0),
child: Directionality(
textDirection: TextDirection.ltr,
child: Material(
child: PageView(
controller: pageController,
children: <Widget>[
Container(
color: Colors.red,
),
color: Colors.green,
),
Container(
color: Colors.red,
),
],
Container(
child: TextField(
controller: textController,
),
color: Colors.green,
),
Container(
color: Colors.red,
),
],
),
),
),
),
......
......@@ -809,23 +809,25 @@ void main() {
return StatefulBuilder(
builder: (BuildContext context, StateSetter setter) {
setState = setter;
return MediaQuery(
data: const MediaQueryData(devicePixelRatio: 1.0),
child: Directionality(
textDirection: TextDirection.ltr,
child: Center(
child: Material(
child: EditableText(
backgroundCursorColor: Colors.grey,
controller: currentController,
focusNode: focusNode,
style: Typography(platform: TargetPlatform.android)
.black
.subhead,
cursorColor: Colors.blue,
selectionControls: materialTextSelectionControls,
keyboardType: TextInputType.text,
onChanged: (String value) { },
return MaterialApp(
home: MediaQuery(
data: const MediaQueryData(devicePixelRatio: 1.0),
child: Directionality(
textDirection: TextDirection.ltr,
child: Center(
child: Material(
child: EditableText(
backgroundCursorColor: Colors.grey,
controller: currentController,
focusNode: focusNode,
style: Typography(platform: TargetPlatform.android)
.black
.subhead,
cursorColor: Colors.blue,
selectionControls: materialTextSelectionControls,
keyboardType: TextInputType.text,
onChanged: (String value) { },
),
),
),
),
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment