Skip to content

Commit 9fccb32

Browse files
authored
Various improvements to text-editing-related documentation. (#142561)
1 parent 4becae2 commit 9fccb32

9 files changed

Lines changed: 126 additions & 115 deletions

File tree

packages/flutter/lib/src/cupertino/text_field.dart

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -763,15 +763,14 @@ class CupertinoTextField extends StatefulWidget {
763763
);
764764
}
765765

766-
/// {@macro flutter.widgets.magnifier.TextMagnifierConfiguration.intro}
766+
/// Configuration for the text field magnifier.
767767
///
768-
/// {@macro flutter.widgets.magnifier.intro}
769-
///
770-
/// {@macro flutter.widgets.magnifier.TextMagnifierConfiguration.details}
768+
/// By default (when this property is set to null), a [CupertinoTextMagnifier]
769+
/// is used on mobile platforms, and nothing on desktop platforms. To suppress
770+
/// the magnifier on all platforms, consider passing
771+
/// [TextMagnifierConfiguration.disabled] explicitly.
771772
///
772-
/// By default, builds a [CupertinoTextMagnifier] on iOS and Android nothing on all other
773-
/// platforms. If it is desired to suppress the magnifier, consider passing
774-
/// [TextMagnifierConfiguration.disabled].
773+
/// {@macro flutter.widgets.magnifier.intro}
775774
///
776775
/// {@tool dartpad}
777776
/// This sample demonstrates how to customize the magnifier that this text field uses.

packages/flutter/lib/src/material/selectable_text.dart

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -502,15 +502,13 @@ class SelectableText extends StatefulWidget {
502502
);
503503
}
504504

505-
/// {@macro flutter.widgets.magnifier.TextMagnifierConfiguration.intro}
506-
///
507-
/// {@macro flutter.widgets.magnifier.intro}
508-
///
509-
/// {@macro flutter.widgets.magnifier.TextMagnifierConfiguration.details}
505+
/// The configuration for the magnifier used when the text is selected.
510506
///
511507
/// By default, builds a [CupertinoTextMagnifier] on iOS and [TextMagnifier]
512-
/// on Android, and builds nothing on all other platforms. If it is desired to
513-
/// suppress the magnifier, consider passing [TextMagnifierConfiguration.disabled].
508+
/// on Android, and builds nothing on all other platforms. To suppress the
509+
/// magnifier, consider passing [TextMagnifierConfiguration.disabled].
510+
///
511+
/// {@macro flutter.widgets.magnifier.intro}
514512
final TextMagnifierConfiguration? magnifierConfiguration;
515513

516514
@override

packages/flutter/lib/src/material/selection_area.dart

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ import 'theme.dart';
3333
/// {@end-tool}
3434
///
3535
/// See also:
36+
///
3637
/// * [SelectableRegion], which provides an overview of the selection system.
3738
class SelectionArea extends StatefulWidget {
3839
/// Creates a [SelectionArea].
@@ -48,15 +49,13 @@ class SelectionArea extends StatefulWidget {
4849
required this.child,
4950
});
5051

51-
/// {@macro flutter.widgets.magnifier.TextMagnifierConfiguration.intro}
52-
///
53-
/// {@macro flutter.widgets.magnifier.intro}
54-
///
55-
/// {@macro flutter.widgets.magnifier.TextMagnifierConfiguration.details}
52+
/// The configuration for the magnifier in the selection region.
5653
///
5754
/// By default, builds a [CupertinoTextMagnifier] on iOS and [TextMagnifier]
58-
/// on Android, and builds nothing on all other platforms. If it is desired to
59-
/// suppress the magnifier, consider passing [TextMagnifierConfiguration.disabled].
55+
/// on Android, and builds nothing on all other platforms. To suppress the
56+
/// magnifier, consider passing [TextMagnifierConfiguration.disabled].
57+
///
58+
/// {@macro flutter.widgets.magnifier.intro}
6059
final TextMagnifierConfiguration? magnifierConfiguration;
6160

6261
/// {@macro flutter.widgets.Focus.focusNode}

packages/flutter/lib/src/material/text_field.dart

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -349,15 +349,13 @@ class TextField extends StatefulWidget {
349349
keyboardType = keyboardType ?? (maxLines == 1 ? TextInputType.text : TextInputType.multiline),
350350
enableInteractiveSelection = enableInteractiveSelection ?? (!readOnly || !obscureText);
351351

352-
/// {@macro flutter.widgets.magnifier.TextMagnifierConfiguration.intro}
353-
///
354-
/// {@macro flutter.widgets.magnifier.intro}
355-
///
356-
/// {@macro flutter.widgets.magnifier.TextMagnifierConfiguration.details}
352+
/// The configuration for the magnifier of this text field.
357353
///
358354
/// By default, builds a [CupertinoTextMagnifier] on iOS and [TextMagnifier]
359-
/// on Android, and builds nothing on all other platforms. If it is desired to
360-
/// suppress the magnifier, consider passing [TextMagnifierConfiguration.disabled].
355+
/// on Android, and builds nothing on all other platforms. To suppress the
356+
/// magnifier, consider passing [TextMagnifierConfiguration.disabled].
357+
///
358+
/// {@macro flutter.widgets.magnifier.intro}
361359
///
362360
/// {@tool dartpad}
363361
/// This sample demonstrates how to customize the magnifier that this text field uses.

packages/flutter/lib/src/widgets/editable_text.dart

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1799,11 +1799,28 @@ class EditableText extends StatefulWidget {
17991799
/// {@template flutter.widgets.EditableText.contextMenuBuilder}
18001800
/// Builds the text selection toolbar when requested by the user.
18011801
///
1802-
/// `primaryAnchor` is the desired anchor position for the context menu, while
1803-
/// `secondaryAnchor` is the fallback location if the menu doesn't fit.
1802+
/// The context menu is built when [EditableTextState.showToolbar] is called,
1803+
/// typically by one of the callbacks installed by the widget created by
1804+
/// [TextSelectionGestureDetectorBuilder.buildGestureDetector]. The widget
1805+
/// returned by [contextMenuBuilder] is passed to a [ContextMenuController].
18041806
///
1805-
/// `buttonItems` represents the buttons that would be built by default for
1806-
/// this widget.
1807+
/// If no callback is provided, no context menu will be shown.
1808+
///
1809+
/// The [EditableTextContextMenuBuilder] signature used by the
1810+
/// [contextMenuBuilder] callback has two parameters, the [BuildContext] of
1811+
/// the [EditableText] and the [EditableTextState] of the [EditableText].
1812+
///
1813+
/// The [EditableTextState] has two properties that are especially useful when
1814+
/// building the widgets for the context menu:
1815+
///
1816+
/// * [EditableTextState.contextMenuAnchors] specifies the desired anchor
1817+
/// position for the context menu.
1818+
///
1819+
/// * [EditableTextState.contextMenuButtonItems] represents the buttons that
1820+
/// should typically be built for this widget (e.g. cut, copy, paste).
1821+
///
1822+
/// The [TextSelectionToolbarLayoutDelegate] class may be particularly useful
1823+
/// in honoring the preferred anchor positions.
18071824
///
18081825
/// For backwards compatibility, when [selectionControls] is set to an object
18091826
/// that does not mix in [TextSelectionHandleControls], [contextMenuBuilder]
@@ -1834,8 +1851,6 @@ class EditableText extends StatefulWidget {
18341851
/// * [BrowserContextMenu], which allows the browser's context menu on web
18351852
/// to be disabled and Flutter-rendered context menus to appear.
18361853
/// {@endtemplate}
1837-
///
1838-
/// If not provided, no context menu will be shown.
18391854
final EditableTextContextMenuBuilder? contextMenuBuilder;
18401855

18411856
/// {@template flutter.widgets.EditableText.spellCheckConfiguration}
@@ -1852,11 +1867,10 @@ class EditableText extends StatefulWidget {
18521867
/// {@endtemplate}
18531868
final SpellCheckConfiguration? spellCheckConfiguration;
18541869

1855-
/// {@macro flutter.widgets.magnifier.TextMagnifierConfiguration.intro}
1870+
/// The configuration for the magnifier to use with selections in this text
1871+
/// field.
18561872
///
18571873
/// {@macro flutter.widgets.magnifier.intro}
1858-
///
1859-
/// {@macro flutter.widgets.magnifier.TextMagnifierConfiguration.details}
18601874
final TextMagnifierConfiguration magnifierConfiguration;
18611875

18621876
bool get _userSelectionEnabled => enableInteractiveSelection && (!readOnly || !obscureText);

packages/flutter/lib/src/widgets/magnifier.dart

Lines changed: 55 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,17 @@ import 'inherited_theme.dart';
1515
import 'navigator.dart';
1616
import 'overlay.dart';
1717

18-
/// {@template flutter.widgets.magnifier.MagnifierBuilder}
1918
/// Signature for a builder that builds a [Widget] with a [MagnifierController].
2019
///
21-
/// Consuming [MagnifierController] or [ValueNotifier]<[MagnifierInfo]> is not
22-
/// required, although if a Widget intends to have entry or exit animations, it should take
23-
/// [MagnifierController] and provide it an [AnimationController], so that [MagnifierController]
24-
/// can wait before removing it from the overlay.
25-
/// {@endtemplate}
20+
/// The builder is called exactly once per magnifier.
2621
///
27-
/// See also:
22+
/// If the `controller` parameter's [MagnifierController.animationController]
23+
/// field is set (by the builder) to an [AnimationController], the
24+
/// [MagnifierController] will drive the animation during entry and exit.
2825
///
29-
/// - [MagnifierInfo], the data class that updates the
30-
/// magnifier.
26+
/// The `magnifierInfo` parameter is updated with new [MagnifierInfo] instances
27+
/// during the lifetime of the built magnifier, e.g. as the user moves their
28+
/// finger around the text field.
3129
typedef MagnifierBuilder = Widget? Function(
3230
BuildContext context,
3331
MagnifierController controller,
@@ -57,9 +55,9 @@ class MagnifierInfo {
5755
/// The offset of the gesture position that the magnifier should be shown at.
5856
final Offset globalGesturePosition;
5957

60-
/// The rect of the current line the magnifier should be shown at,
61-
/// without taking into account any padding of the field; only the position
62-
/// of the first and last character.
58+
/// The rect of the current line the magnifier should be shown at, without
59+
/// taking into account any padding of the field; only the position of the
60+
/// first and last character.
6361
final Rect currentLineBoundaries;
6462

6563
/// The rect of the handle that the magnifier should follow.
@@ -89,48 +87,45 @@ class MagnifierInfo {
8987
);
9088
}
9189

92-
/// {@template flutter.widgets.magnifier.TextMagnifierConfiguration.intro}
93-
/// A configuration object for a magnifier.
94-
/// {@endtemplate}
90+
/// A configuration object for a magnifier (e.g. in a text field).
9591
///
96-
/// {@macro flutter.widgets.magnifier.intro}
97-
///
98-
/// {@template flutter.widgets.magnifier.TextMagnifierConfiguration.details}
99-
/// In general, most features of the magnifier can be configured through
100-
/// [MagnifierBuilder]. [TextMagnifierConfiguration] is used to configure
101-
/// the magnifier's behavior through the [SelectionOverlay].
102-
/// {@endtemplate}
92+
/// In general, most features of the magnifier can be configured by controlling
93+
/// the widgets built by the [magnifierBuilder].
10394
class TextMagnifierConfiguration {
10495
/// Constructs a [TextMagnifierConfiguration] from parts.
10596
///
10697
/// If [magnifierBuilder] is null, a default [MagnifierBuilder] will be used
107-
/// that never builds a magnifier.
98+
/// that does not build a magnifier.
10899
const TextMagnifierConfiguration({
109100
MagnifierBuilder? magnifierBuilder,
110-
this.shouldDisplayHandlesInMagnifier = true
101+
this.shouldDisplayHandlesInMagnifier = true,
111102
}) : _magnifierBuilder = magnifierBuilder;
112103

113-
/// The passed in [MagnifierBuilder].
114-
///
115-
/// This is nullable because [disabled] needs to be static const,
116-
/// so that it can be used as a default parameter. If left null,
117-
/// the [magnifierBuilder] getter will be a function that always returns
118-
/// null.
104+
/// The builder callback that creates the widget that renders the magnifier.
105+
MagnifierBuilder get magnifierBuilder => _magnifierBuilder ?? _none;
119106
final MagnifierBuilder? _magnifierBuilder;
120107

121-
/// {@macro flutter.widgets.magnifier.MagnifierBuilder}
122-
MagnifierBuilder get magnifierBuilder => _magnifierBuilder ?? (_, __, ___) => null;
108+
static Widget? _none(
109+
BuildContext context,
110+
MagnifierController controller,
111+
ValueNotifier<MagnifierInfo> magnifierInfo,
112+
) => null;
123113

124-
/// Determines whether a magnifier should show the text editing handles or not.
114+
/// Whether a magnifier should show the text editing handles or not.
115+
///
116+
/// This flag is used by [SelectionOverlay.showMagnifier] to control the order
117+
/// of layers in the rendering; specifically, whether to place the layer
118+
/// containing the handles above or below the layer containing the magnifier
119+
/// in the [Overlay].
125120
final bool shouldDisplayHandlesInMagnifier;
126121

127-
/// A constant for a [TextMagnifierConfiguration] that is disabled.
128-
///
129-
/// In particular, this [TextMagnifierConfiguration] is considered disabled
130-
/// because it never builds anything, regardless of platform.
122+
/// A constant for a [TextMagnifierConfiguration] that is disabled, meaning it
123+
/// never builds anything, regardless of platform.
131124
static const TextMagnifierConfiguration disabled = TextMagnifierConfiguration();
132125
}
133126

127+
/// A controller for a magnifier.
128+
///
134129
/// [MagnifierController]'s main benefit over holding a raw [OverlayEntry] is that
135130
/// [MagnifierController] will handle logic around waiting for a magnifier to animate in or out.
136131
///
@@ -156,11 +151,11 @@ class MagnifierController {
156151

157152
/// The magnifier's [OverlayEntry], if currently in the overlay.
158153
///
159-
/// This is public in case other overlay entries need to be positioned
160-
/// above or below this [overlayEntry]. Anything in the paint order after
161-
/// the [RawMagnifier] will not be displayed in the magnifier; this means that if it
162-
/// is desired for an overlay entry to be displayed in the magnifier,
163-
/// it _must_ be positioned below the magnifier.
154+
/// This is exposed so that other overlay entries can be positioned above or
155+
/// below this [overlayEntry]. Anything in the paint order after the
156+
/// [RawMagnifier] in this [OverlayEntry] will not be displayed in the
157+
/// magnifier; if it is desired for an overlay entry to be displayed in the
158+
/// magnifier, it _must_ be positioned below the magnifier.
164159
///
165160
/// {@tool snippet}
166161
/// ```dart
@@ -198,20 +193,22 @@ class MagnifierController {
198193
/// ```
199194
/// {@end-tool}
200195
///
201-
/// A null check on [overlayEntry] will not suffice to check if a magnifier is in the
202-
/// overlay or not; instead, you should check [shown]. This is because it is possible,
203-
/// such as in cases where [hide] was called with `removeFromOverlay` false, that the magnifier
204-
/// is not shown, but the entry is not null.
196+
/// To check if a magnifier is in the overlay, use [shown]. The [overlayEntry]
197+
/// field may be non-null even when the magnifier is not visible.
205198
OverlayEntry? get overlayEntry => _overlayEntry;
206199
OverlayEntry? _overlayEntry;
207200

208-
/// If the magnifier is shown or not.
201+
/// Whether the magnifier is currently being shown.
202+
///
203+
/// This is false when nothing is in the overlay, when the
204+
/// [animationController] is in the [AnimationStatus.dismissed] state, or when
205+
/// the [animationController] is animating out (i.e. in the
206+
/// [AnimationStatus.reverse] state).
209207
///
210-
/// [shown] is:
211-
/// - false when nothing is in the overlay.
212-
/// - false when [animationController] is [AnimationStatus.dismissed].
213-
/// - false when [animationController] is animating out.
214-
/// and true in all other circumstances.
208+
/// It is true in the opposite cases, i.e. when the overlay is not empty, and
209+
/// either the [animationController] is null, in the
210+
/// [AnimationStatus.completed] state, or in the [AnimationStatus.forward]
211+
/// state.
215212
bool get shown {
216213
if (overlayEntry == null) {
217214
return false;
@@ -225,17 +222,17 @@ class MagnifierController {
225222
return true;
226223
}
227224

228-
/// Shows the [RawMagnifier] that this controller controls.
225+
/// Displays the magnifier.
229226
///
230227
/// Returns a future that completes when the magnifier is fully shown, i.e. done
231228
/// with its entry animation.
232229
///
233-
/// To control what overlays are shown in the magnifier, utilize [below]. See
234-
/// [overlayEntry] for more details on how to utilize [below].
230+
/// To control what overlays are shown in the magnifier, use `below`. See
231+
/// [overlayEntry] for more details on how to utilize `below`.
235232
///
236-
/// If the magnifier already exists (i.e. [overlayEntry] != null), then [show] will
237-
/// override the old overlay and not play an exit animation. Consider awaiting [hide]
238-
/// first, to guarantee
233+
/// If the magnifier already exists (i.e. [overlayEntry] != null), then [show]
234+
/// will replace the old overlay without playing an exit animation. Consider
235+
/// awaiting [hide] first, to animate from the old magnifier to the new one.
239236
Future<void> show({
240237
required BuildContext context,
241238
required WidgetBuilder builder,

packages/flutter/lib/src/widgets/selectable_region.dart

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,7 @@ const double _kSelectableVerticalComparingThreshold = 3.0;
192192
/// ```
193193
///
194194
/// See also:
195+
///
195196
/// * [SelectionArea], which creates a [SelectableRegion] with
196197
/// platform-adaptive selection controls.
197198
/// * [SelectionHandler], which contains APIs to handle selection events from the
@@ -216,13 +217,13 @@ class SelectableRegion extends StatefulWidget {
216217
this.onSelectionChanged,
217218
});
218219

219-
/// {@macro flutter.widgets.magnifier.TextMagnifierConfiguration.intro}
220-
///
221-
/// {@macro flutter.widgets.magnifier.intro}
220+
/// The configuration for the magnifier used with selections in this region.
222221
///
223222
/// By default, [SelectableRegion]'s [TextMagnifierConfiguration] is disabled.
223+
/// For a version of [SelectableRegion] that adapts automatically to the
224+
/// current platform, consider [SelectionArea].
224225
///
225-
/// {@macro flutter.widgets.magnifier.TextMagnifierConfiguration.details}
226+
/// {@macro flutter.widgets.magnifier.intro}
226227
final TextMagnifierConfiguration magnifierConfiguration;
227228

228229
/// {@macro flutter.widgets.Focus.focusNode}

0 commit comments

Comments
 (0)