This tutorial shows you how to create a TextField
or TextFormField
that accepts numeric values within an allowed range.
In Flutter, you can create a text field for inputting numbers by using a TextField
or TextFormField
. It's possible to make it accepts numeric only values by adding an appropriate TextInputFormatter
. If you don't know yet, you can read our tutorial about how to create a text field that accepts numeric values only..
In many cases, there is a range for valid values. In other words, there is a minimum value and a maximum value that the users can input. Therefore, you need to customize the text field so that it doesn't accept values outside the range. If you have that requirement, you can read the examples below.
Set Max Length
If the maximum allowed value is based on the number of character length, you can use the maxLength
argument of TextField
or TextFormField
.
TextField(
maxLength: 3,
// Other arguments
)
Create Custom Formatter
Flutter's TextField
and TextFormField
have an argument inputFormatters
where you can pass a list of TextInputFormatter
s. A TextInputFormatter
can be used to add validation and formatting when the value changes. You can create your own with your custom logic.
For this purpose, we are going to create a custom TextInputFormatter
for limiting the allowed numeric values. If the value is not within the allowed range, we need to replace it with a valid value. If it's smaller than the minimum value, it will be set to the minimum value. If it's bigger than the maximum value, it will be set to the maximum value. In addition, we should not update the input if it's not parseable to a number.
To create a custom TextInputFormatter
, it's required to override the formatEditUpdate
method. It has two parameters of type TextEditingValue
and also returns a TextEditingValue
. The first parameter represents the old value, while the second represents the new value.
For setting the minimum and maximum values, we need to check the new value. If it's empty, just return it as-is (no need to validate). If it's not parseable (e.g. contains invalid characters), just return the old value. Next, check whether it's within allowed range. If it's smaller than the minimum value, just return the smallest valid number. If it's bigger than the maximum value, just return the biggest valid number. Otherwise, the value is valid.
The formatter below has configurable min
and max
values, so it can be reused in many text fields.
class NumericRangeFormatter extends TextInputFormatter {
final double min;
final double max;
NumericRangeFormatter({required this.min, required this.max});
@override
TextEditingValue formatEditUpdate(
TextEditingValue oldValue,
TextEditingValue newValue,
) {
if (newValue.text.isEmpty) {
return newValue;
}
final newValueNumber = double.tryParse(newValue.text);
if (newValueNumber == null) {
return oldValue;
}
if (newValueNumber < min) {
return newValue.copyWith(text: min.toString());
} else if (newValueNumber > max) {
return newValue.copyWith(text: max.toString());
} else {
return newValue;
}
}
}
Then, create an instance of the formatter and pass it as one of the input formatters.
TextField(
inputFormatters: [
// Other formatters
NumericRangeFormatter(min: 1, max: 100),
],
// Other arguments
)
Full Code
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Woolha.com Flutter Tutorial',
home: Home(),
debugShowCheckedModeBanner: false,
);
}
}
class Home extends StatefulWidget {
const Home({super.key});
@override
State<StatefulWidget> createState() {
return HomeState();
}
}
class HomeState extends State<Home> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Woolha.com Flutter Tutorial'),
backgroundColor: Colors.teal,
),
body: Padding(
padding: const EdgeInsets.all(10),
child: Column(
children: [
TextField(
maxLength: 3,
decoration: const InputDecoration(
border: UnderlineInputBorder(),
labelText: 'Score',
labelStyle: TextStyle(color: Colors.teal, fontSize: 20),
),
keyboardType: TextInputType.number,
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
// To allow decimal point and/or signed numbers, read our tutorial
// https://www.woolha.com/tutorials/flutter-create-number-only-textfield-textformfield
NumericRangeFormatter(min: 1, max: 100),
],
),
],
),
),
);
}
}
// See the code above for NumericRangeFormatter
Summary
If you only want to limit the length of the inputted numbers, setting the maxLength
argument is enough. Otherwise, you may need to create and pass a custom TextInputFormatter
. This tutorial provides an example of how to create a custom formatter that forces the inputted values to be always within a specified range.
You can also read about:
- How to create a text field with currency format in Flutter, in case you want to format the input in a currency format