Skip to content

Commit

Permalink
TextField context menu should fade on scroll on mobile devices (flutt…
Browse files Browse the repository at this point in the history
…er#138313)

This change affects Android and iOS devices using the TextField's context menu. After this change the context menu will fade out when scrolling the text and fade in when the scroll ends. 

If the scroll ends and the selection is outside of the view, then the toolbar will be scheduled to show in a future scroll end. This toolbar scheduling can be invalidated if the `TextEditingValue` changed anytime between the scheduling and when the toolbar is ready to be shown.

This change also fixes a regression where the TextField context menu would not fade when the selection handles where not visible.

When using the native browser context menu this behavior is not controlled by Flutter.

https://github.com/flutter/flutter/assets/948037/3f46bcbb-ba6f-456c-8473-e42919b9d572

Fixes flutter#52425
Fixes flutter#105804
Fixes flutter#52426
  • Loading branch information
Renzo-Olivares authored Feb 6, 2024
1 parent 6322fef commit 0903bf7
Show file tree
Hide file tree
Showing 8 changed files with 688 additions and 110 deletions.
8 changes: 8 additions & 0 deletions packages/flutter/lib/src/cupertino/text_field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,14 @@ class _CupertinoTextFieldSelectionGestureDetectorBuilder extends TextSelectionGe
///
/// {@macro flutter.widgets.editableText.showCaretOnScreen}
///
/// ## Scrolling Considerations
///
/// If this [CupertinoTextField] is not a descendant of [Scaffold] and is being
/// used within a [Scrollable] or nested [Scrollable]s, consider placing a
/// [ScrollNotificationObserver] above the root [Scrollable] that contains this
/// [CupertinoTextField] to ensure proper scroll coordination for
/// [CupertinoTextField] and its components like [TextSelectionOverlay].
///
/// See also:
///
/// * <https://developer.apple.com/documentation/uikit/uitextfield>
Expand Down
8 changes: 8 additions & 0 deletions packages/flutter/lib/src/material/selectable_text.dart
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,14 @@ class _SelectableTextSelectionGestureDetectorBuilder extends TextSelectionGestur
/// To make [SelectableText] react to touch events, use callback [onTap] to achieve
/// the desired behavior.
///
/// ## Scrolling Considerations
///
/// If this [SelectableText] is not a descendant of [Scaffold] and is being used
/// within a [Scrollable] or nested [Scrollable]s, consider placing a
/// [ScrollNotificationObserver] above the root [Scrollable] that contains this
/// [SelectableText] to ensure proper scroll coordination for [SelectableText]
/// and its components like [TextSelectionOverlay].
///
/// See also:
///
/// * [Text], which is the non selectable version of this widget.
Expand Down
8 changes: 8 additions & 0 deletions packages/flutter/lib/src/material/text_field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,14 @@ class _TextFieldSelectionGestureDetectorBuilder extends TextSelectionGestureDete
/// ** See code in examples/api/lib/material/text_field/text_field.2.dart **
/// {@end-tool}
///
/// ## Scrolling Considerations
///
/// If this [TextField] is not a descendant of [Scaffold] and is being used
/// within a [Scrollable] or nested [Scrollable]s, consider placing a
/// [ScrollNotificationObserver] above the root [Scrollable] that contains this
/// [TextField] to ensure proper scroll coordination for [TextField] and its
/// components like [TextSelectionOverlay].
///
/// See also:
///
/// * [TextFormField], which integrates with the [Form] widget.
Expand Down
375 changes: 286 additions & 89 deletions packages/flutter/lib/src/widgets/editable_text.dart

Large diffs are not rendered by default.

5 changes: 3 additions & 2 deletions packages/flutter/lib/src/widgets/text_selection.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1432,6 +1432,7 @@ class SelectionOverlay {
context: context,
contextMenuBuilder: (BuildContext context) {
return _SelectionToolbarWrapper(
visibility: toolbarVisible,
layerLink: toolbarLayerLink,
offset: -renderBox.localToGlobal(Offset.zero),
child: contextMenuBuilder(context),
Expand Down Expand Up @@ -2228,8 +2229,6 @@ class TextSelectionGestureDetectorBuilder {
switch (defaultTargetPlatform) {
case TargetPlatform.android:
case TargetPlatform.fuchsia:
// On mobile platforms the selection is set on tap up.
editableText.hideToolbar(false);
case TargetPlatform.iOS:
// On mobile platforms the selection is set on tap up.
break;
Expand Down Expand Up @@ -2352,13 +2351,15 @@ class TextSelectionGestureDetectorBuilder {
break;
// On desktop platforms the selection is set on tap down.
case TargetPlatform.android:
editableText.hideToolbar(false);
if (isShiftPressedValid) {
_extendSelection(details.globalPosition, SelectionChangedCause.tap);
return;
}
renderEditable.selectPosition(cause: SelectionChangedCause.tap);
editableText.showSpellCheckSuggestionsToolbar();
case TargetPlatform.fuchsia:
editableText.hideToolbar(false);
if (isShiftPressedValid) {
_extendSelection(details.globalPosition, SelectionChangedCause.tap);
return;
Expand Down
4 changes: 2 additions & 2 deletions packages/flutter/test/cupertino/text_field_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10034,7 +10034,7 @@ void main() {
skip: kIsWeb, // [intended]
);

testWidgets('text selection toolbar is hidden on tap down', (WidgetTester tester) async {
testWidgets('text selection toolbar is hidden on tap down on desktop platforms', (WidgetTester tester) async {
final TextEditingController controller = TextEditingController(
text: 'blah1 blah2',
);
Expand Down Expand Up @@ -10077,7 +10077,7 @@ void main() {
expect(find.byType(CupertinoAdaptiveTextSelectionToolbar), findsNothing);
},
skip: isContextMenuProvidedByPlatform, // [intended] only applies to platforms where we supply the context menu.
variant: TargetPlatformVariant.all(excluding: <TargetPlatform>{ TargetPlatform.iOS }),
variant: TargetPlatformVariant.all(excluding: TargetPlatformVariant.mobile().values),
);

testWidgets('Does not shrink in height when enters text when there is large single-line placeholder', (WidgetTester tester) async {
Expand Down
Loading

0 comments on commit 0903bf7

Please sign in to comment.