mirror of
https://github.com/flutter/flutter
synced 2024-10-13 19:52:53 +00:00
Optionally show the text field length but not the max (#24183)
If maxLength is set to TextField.noMaxLength then continue to show the character counter but do not display the max input length value.
This commit is contained in:
parent
779c68f691
commit
87156df6d9
|
@ -78,7 +78,10 @@ class TextField extends StatefulWidget {
|
|||
/// number of characters allowed in the text field is not restricted. If
|
||||
/// [maxLength] is set, a character counter will be displayed below the
|
||||
/// field, showing how many characters have been entered and how many are
|
||||
/// allowed. After [maxLength] characters have been input, additional input
|
||||
/// allowed unless the value is set to [noMaxLength] in which case only the
|
||||
/// current length is displayed.
|
||||
///
|
||||
/// After [maxLength] characters have been input, additional input
|
||||
/// is ignored, unless [maxLengthEnforced] is set to false. The TextField
|
||||
/// enforces the length with a [LengthLimitingTextInputFormatter], which is
|
||||
/// evaluated after the supplied [inputFormatters], if any. The [maxLength]
|
||||
|
@ -192,6 +195,10 @@ class TextField extends StatefulWidget {
|
|||
/// {@macro flutter.widgets.editableText.maxLines}
|
||||
final int maxLines;
|
||||
|
||||
/// If [maxLength] is set to this value, only the "current input length"
|
||||
/// part of the character counter is shown.
|
||||
static const int noMaxLength = 9007199254740992; // math.pow(2, 53);
|
||||
|
||||
/// The maximum number of characters (Unicode scalar values) to allow in the
|
||||
/// text field.
|
||||
///
|
||||
|
@ -339,9 +346,16 @@ class _TextFieldState extends State<TextField> with AutomaticKeepAliveClientMixi
|
|||
return effectiveDecoration;
|
||||
|
||||
final int currentLength = _effectiveController.value.text.runes.length;
|
||||
final String counterText = '$currentLength/${widget.maxLength}';
|
||||
final int remaining = (widget.maxLength - currentLength).clamp(0, widget.maxLength);
|
||||
final String semanticCounterText = localizations.remainingTextFieldCharacterCount(remaining);
|
||||
String counterText = '$currentLength';
|
||||
String semanticCounterText = '';
|
||||
|
||||
if (widget.maxLength != TextField.noMaxLength) {
|
||||
counterText += '/${widget.maxLength}';
|
||||
final int remaining = (widget.maxLength - currentLength).clamp(0, widget.maxLength);
|
||||
semanticCounterText = localizations.remainingTextFieldCharacterCount(remaining);
|
||||
}
|
||||
|
||||
// Handle length exceeds maxLength
|
||||
if (_effectiveController.value.text.runes.length > widget.maxLength) {
|
||||
final ThemeData themeData = Theme.of(context);
|
||||
return effectiveDecoration.copyWith(
|
||||
|
|
|
@ -1790,16 +1790,14 @@ void main() {
|
|||
testWidgets('setting maxLength shows counter', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(const MaterialApp(
|
||||
home: Material(
|
||||
child: DefaultTextStyle(
|
||||
style: TextStyle(fontFamily: 'Ahem', fontSize: 10.0),
|
||||
child: Center(
|
||||
child: Center(
|
||||
child: TextField(
|
||||
maxLength: 10,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
||||
);
|
||||
|
||||
expect(find.text('0/10'), findsOneWidget);
|
||||
|
||||
|
@ -1809,22 +1807,41 @@ void main() {
|
|||
expect(find.text('5/10'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets(
|
||||
'setting maxLength to TextField.noMaxLength shows only entered length',
|
||||
(WidgetTester tester) async {
|
||||
await tester.pumpWidget(const MaterialApp(
|
||||
home: Material(
|
||||
child: Center(
|
||||
child: TextField(
|
||||
maxLength: TextField.noMaxLength,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(find.text('0'), findsOneWidget);
|
||||
|
||||
await tester.enterText(find.byType(TextField), '01234');
|
||||
await tester.pump();
|
||||
|
||||
expect(find.text('5'), findsOneWidget);
|
||||
});
|
||||
|
||||
testWidgets('TextField identifies as text field in semantics', (WidgetTester tester) async {
|
||||
final SemanticsTester semantics = SemanticsTester(tester);
|
||||
|
||||
await tester.pumpWidget(
|
||||
const MaterialApp(
|
||||
home: Material(
|
||||
child: DefaultTextStyle(
|
||||
style: TextStyle(fontFamily: 'Ahem', fontSize: 10.0),
|
||||
child: Center(
|
||||
child: Center(
|
||||
child: TextField(
|
||||
maxLength: 10,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
expect(semantics, includesNodeWith(flags: <SemanticsFlag>[SemanticsFlag.isTextField]));
|
||||
|
@ -3162,9 +3179,7 @@ void main() {
|
|||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: DefaultTextStyle(
|
||||
style: const TextStyle(fontSize: 12.0, fontFamily: 'Ahem'),
|
||||
child: MediaQuery(
|
||||
body: MediaQuery(
|
||||
data: MediaQueryData.fromWindow(ui.window).copyWith(textScaleFactor: 4.0),
|
||||
child: Center(
|
||||
child: TextField(
|
||||
|
@ -3175,7 +3190,6 @@ void main() {
|
|||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
await tester.tap(find.byType(TextField));
|
||||
|
|
Loading…
Reference in a new issue