A TextFormField widget that has a dropdown list for units and provides conversion.
You can use it almost like the original TextFormField form field, with a few additions.
First, it has a generic type, the type of the unit you want to use. Let's suppose we need the following three length units:
enum SizeUnits { Millimeter, Inch, LightNanosecond }We prepare a map with the user readable names:
static final unitNames = {
SizeUnits.Millimeter: 'mm',
SizeUnits.Inch: '"',
SizeUnits.LightNanosecond: 'light-ns',
};And a function that can receive a value in one unit and has to convert it to another one:
double _sizeConverter(SizeUnits fromUnit, SizeUnits toUnit, double value) {
final valueMm = switch (fromUnit) {
SizeUnits.Millimeter => value,
SizeUnits.Inch => value * 25.4,
SizeUnits.LightNanosecond => value * 299.792458,
};
return switch (toUnit) {
SizeUnits.Millimeter => valueMm,
SizeUnits.Inch => valueMm / 25.4,
SizeUnits.LightNanosecond => valueMm / 299.792458,
};
}We pass these – and any other usual TextFormField stuff you need – to the field.
TextFormUnitField<SizeUnits>(
controller: controller,
keyboardType: TextInputType.number,
inputFormatters: [FilteringTextInputFormatter.allow(allowed)],
textInputAction: TextInputAction.next,
icon: const Icon(Icons.height),
labelText: 'Size',
units: unitNames,
initialUnit: SizeUnits.Millimeter,
unitIcon: const Icon(Icons.keyboard_arrow_down),
converter: _sizeConverter,
onSaved: (value) {
if (value != null) print('${value.value} ${unitNames[value.unit]}');
},
),When it calls back for validation or saving, it passes a ValueWithUnit<T> value where T is our unit type.
You can set the value of the field by setting text on the controller, as usual (eg. with nice formatting of the value):
controller.text = NumberFormat.decimalPattern().format(newValue);If you use a TextFormUnitController<T> instead of a standard TextEditingController, you can also
controller.doSetValue(double value)that does exactly the above for you, or you can change the unit (with or without making a conversion) with:
controller.setUnit(T unit, {bool convert = false})Make sure you specify the T unit type when you create the controller or you get an exception.
If you like this package, please consider supporting it.
