File tree Expand file tree Collapse file tree 7 files changed +55
-4
lines changed
dev/integration_tests/flutter_gallery/lib/demo/material Expand file tree Collapse file tree 7 files changed +55
-4
lines changed Original file line number Diff line number Diff line change @@ -14,7 +14,7 @@ const String _kGalleryAssetsPackage = 'flutter_gallery_assets';
1414class _Page {
1515 _Page ({ this .label });
1616 final String label;
17- String get id => label[ 0 ] ;
17+ String get id => label.characters.first ;
1818 @override
1919 String toString () => '$runtimeType ("$label ")' ;
2020}
Original file line number Diff line number Diff line change @@ -131,6 +131,8 @@ class _CupertinoTextFieldSelectionGestureDetectorBuilder extends TextSelectionGe
131131/// field (e.g., by pressing a button on the soft keyboard), the text field
132132/// calls the [onSubmitted] callback.
133133///
134+ /// {@macro flutter.widgets.editableText.complexCharacters}
135+ ///
134136/// To control the text that is displayed in the text field, use the
135137/// [controller] . For example, to set the initial value of the text field, use
136138/// a [controller] that already contains some text such as:
Original file line number Diff line number Diff line change @@ -43,6 +43,9 @@ import 'theme.dart';
4343/// the [AppBar.leading] position e.g. from the hamburger menu to the back arrow
4444/// used to exit the search page.
4545///
46+ /// ## Handling emojis and other complex characters
47+ /// {@macro flutter.widgets.editableText.complexCharacters}
48+ ///
4649/// See also:
4750///
4851/// * [SearchDelegate] to define the content of the search page.
@@ -85,6 +88,9 @@ Future<T> showSearch<T>({
8588/// A given [SearchDelegate] can only be associated with one active [showSearch]
8689/// call. Call [SearchDelegate.close] before re-using the same delegate instance
8790/// for another [showSearch] call.
91+ ///
92+ /// ## Handling emojis and other complex characters
93+ /// {@macro flutter.widgets.editableText.complexCharacters}
8894abstract class SearchDelegate <T > {
8995
9096 /// Constructor to be called by subclasses which may specify [searchFieldLabel] , [keyboardType] and/or
Original file line number Diff line number Diff line change @@ -227,7 +227,7 @@ class _TextFieldSelectionGestureDetectorBuilder extends TextSelectionGestureDete
227227/// builder: (BuildContext context) {
228228/// return AlertDialog(
229229/// title: const Text('Thanks!'),
230- /// content: Text ('You typed "$value".'),
230+ /// content: Text ('You typed "$value", which has length ${value.characters.length} .'),
231231/// actions: <Widget>[
232232/// TextButton(
233233/// onPressed: () { Navigator.pop(context); },
@@ -256,6 +256,14 @@ class _TextFieldSelectionGestureDetectorBuilder extends TextSelectionGestureDete
256256///
257257/// Keep in mind you can also always read the current string from a TextField's
258258/// [TextEditingController] using [TextEditingController.text] .
259+ ///
260+ /// ## Handling emojis and other complex characters
261+ /// {@macro flutter.widgets.editableText.complexCharacters}
262+ ///
263+ /// In the live Dartpad example above, try typing the emoji 👨👩👦
264+ /// into the field and submitting. Because the example code measures the length
265+ /// with `value.characters.length` , the emoji is correctly counted as a single
266+ /// character.
259267///
260268/// See also:
261269///
Original file line number Diff line number Diff line change @@ -25,6 +25,9 @@ import 'text_input.dart';
2525/// To create custom formatters, extend the [TextInputFormatter] class and
2626/// implement the [formatEditUpdate] method.
2727///
28+ /// ## Handling emojis and other complex characters
29+ /// {@macro flutter.widgets.editableText.complexCharacters}
30+ ///
2831/// See also:
2932///
3033/// * [EditableText] on which the formatting apply.
@@ -300,13 +303,19 @@ class WhitelistingTextInputFormatter extends FilteringTextInputFormatter {
300303}
301304
302305/// A [TextInputFormatter] that prevents the insertion of more characters
303- /// (currently defined as Unicode scalar values) than allowed.
306+ /// than allowed.
304307///
305308/// Since this formatter only prevents new characters from being added to the
306309/// text, it preserves the existing [TextEditingValue.selection] .
307310///
311+ /// Characters are counted as user-perceived characters using the
312+ /// [characters] (https://pub.dev/packages/characters) package, so even complex
313+ /// characters like extended grapheme clusters and surrogate pairs are counted
314+ /// as single characters.
315+ ///
316+ /// See also:
308317/// * [maxLength] , which discusses the precise meaning of "number of
309- /// characters" and how it may differ from the intuitive meaning .
318+ /// characters".
310319class LengthLimitingTextInputFormatter extends TextInputFormatter {
311320 /// Creates a formatter that prevents the insertion of more characters than a
312321 /// limit.
Original file line number Diff line number Diff line change @@ -946,6 +946,22 @@ class EditableText extends StatefulWidget {
946946 /// {@end-tool}
947947 /// {@endtemplate}
948948 ///
949+ /// ## Handling emojis and other complex characters
950+ /// {@template flutter.widgets.editableText.complexCharacters}
951+ /// It's important to always use
952+ /// [characters] (https://pub.dev/packages/characters) when dealing with user
953+ /// input text that may contain complex characters. This will ensure that
954+ /// extended grapheme clusters and surrogate pairs are treated as single
955+ /// characters, as they appear to the user.
956+ ///
957+ /// For example, when finding the length of some user input, use
958+ /// `string.characters.length` . Do NOT use `string.length` or even
959+ /// `string.runes.length` . For the complex character "👨👩👦", this
960+ /// appears to the user as a single character, and `string.characters.length`
961+ /// intuitively returns 1. On the other hand, `string.length` returns 8, and
962+ /// `string.runes.length` returns 5!
963+ /// {@endtemplate}
964+ ///
949965 /// See also:
950966 ///
951967 /// * [inputFormatters] , which are called before [onChanged]
Original file line number Diff line number Diff line change @@ -1571,6 +1571,16 @@ class Navigator extends StatefulWidget {
15711571 /// The [NavigatorState] and [initialRoute] will be passed to the callback.
15721572 /// The callback must return a list of [Route] objects with which the history
15731573 /// will be primed.
1574+ ///
1575+ /// When parsing the initialRoute, if there's any chance that the it may
1576+ /// contain complex characters, it's best to use the
1577+ /// [characters] (https://pub.dev/packages/characters) API. This will ensure
1578+ /// that extended grapheme clusters and surrogate pairs are treated as single
1579+ /// characters by the code, the same way that they appear to the user. For
1580+ /// example, the string "👨👩👦" appears to the user as a single
1581+ /// character and `string.characters.length` intuitively returns 1. On the
1582+ /// other hand, `string.length` returns 8, and `string.runes.length` returns
1583+ /// 5!
15741584 final RouteListFactory onGenerateInitialRoutes;
15751585
15761586 /// Whether this navigator should report route update message back to the
You can’t perform that action at this time.
0 commit comments