I just started learning Flutter and i am trying to figure out how the user can enter an amount in a TextField ,for example 1234567 , should look like this when user is typing :
1.00
12.00
123.00
1 234.00
12 345.00
123 456.00
1 234 567.00
I tried using this library : mask_text_input_formatter, but i can't figure out how to do it. Here is my code
var maskFormatter = new MaskTextInputFormatter(
mask: '### ### ###.00', filter: {"#": RegExp(r'[0-9]')});
TextFormField(
keyboardType: TextInputType.number,
inputFormatters: [maskFormatter],
onChanged: (value) {},
decoration: InputDecoration(
prefixIcon: Icon(Icons.monetization_on),
hintText: 'Amount',
border: OutlineInputBorder(),
),
validator: (value) {
if (value.isEmpty) {
return 'Please enter some text';
}
return null;
},
),
Any idea on how to achieve that result.
Declare and initialize a text controller and assign it to the text field. Update its value on change in input!
TextEditingController _moneyController = TextEditingController();
#override
void initState() {
super.initState();
_moneyController.text = '.00';
}
TextFormField(
keyboardType: TextInputType.number,
inputFormatters: [maskFormatter],
onChanged: (value) {},
decoration: InputDecoration(
prefixIcon: Icon(Icons.monetization_on),
hintText: 'Amount',
border: OutlineInputBorder(),
),
validator: (value) {
if (value.isEmpty) {
return 'Please enter some text';
}
return null;
},
//added code here
controller: _moneyController,
),
Related
Restricts the user's input.
For example, if I set the numeric limit to 4000, the user cannot enter a number greater than 4000.
TextFormField(
//TODO:보유수량 이상 쓰는것 방지할것.
controller: _recruitStockEditingController,
keyboardType: TextInputType.number,
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
decoration: InputDecoration(
contentPadding: EdgeInsets.only(
left: 21.0.w, top: 11.0.h, bottom: 11.0.h),
hintText: "수량을 입력해주세요.",
hintStyle: TextStyle(
fontSize: 14.0.sp, color: const Color(0xff696C75)),
border: OutlineInputBorder(
borderSide: const BorderSide(color: Color(0xffCACBD4)),
borderRadius: BorderRadius.circular(6))),
),
Try this with TextInputFormatter
import 'package:flutter/services.dart';
class NumberLimitFormatter extends TextInputFormatter {
#override
TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
if(newValue.text == "") return newValue;
if(int.parse(newValue.text.toString())<4000){
return newValue;
}
return oldValue;
}
}
Uasge:
TextField(
controller: myController,
keyboardType: TextInputType.number,
inputFormatters: [
NumberLimitFormatter(),
FilteringTextInputFormatter.digitsOnly,
],
),
Using Validator and TextFormField:
TextFormField(
keyboardType: TextInputType.number,
autovalidateMode: AutovalidateMode
.onUserInteraction, // to instantly valid the input
inputFormatters: [
FilteringTextInputFormatter.digitsOnly,
],
validator: (String? value) {
if (value == null || value.isEmpty)
return "Enter number";
else if (int.parse(value) > 4000)
return "Entered number can't be greater than 4000";
else
return null;
}),
try using a validator.
validator: (value) {
if (value > 4000) {
return "You can't enter a value greater than 4000";
}
return null;
},
I have 1 functionality of adding TextFormField in Container on Button press upto 4 TextFormField like below image and when there's no text in TextFormField i want to remove that TextFormField so i have put that login in onChange.
When i press the button 1s time and it will add TextFormField and without typing any character if i press delete button from keyboard onChange is not getting called.
Please see this video: https://drive.google.com/file/d/1Yln48d5JHvvYdb4LRDXxmlzPzlC__xYq/view?usp=sharing
Here is my code.
TextFormField(
controller: bullet2Controller,
focusNode: focusNode2,
maxLines: null,
minLines: 1,
textCapitalization:TextCapitalization.sentences,
cursorColor: Colors.black,
showCursor: true,
autofocus: true,
textAlign: TextAlign.start,
inputFormatters: [LengthLimitingTextInputFormatter(140),],
onChanged: (value) {
setState(() {
if (value.isEmpty) {
isBullet2Visible = false;
if (isBullet1Visible) {
focusNode1.requestFocus();
} else if (isBullet3Visible) {
focusNode3.requestFocus();
} else if (isBullet4Visible) {
focusNode4.requestFocus();
} else {
FocusScope.of(context).unfocus();
}
if (_counter > 0) {
_counter--;
}
}
if (kDebugMode) {
print("${value.length.toString()} character(s)");
}
});
},
decoration: const InputDecoration(disabledBorder:
InputBorder.none,
border:
InputBorder.none,
filled: true,
fillColor: Colors.white,
),
keyboardType:
TextInputType
.multiline,
textInputAction:
TextInputAction.done,
),
Is it default behaviour or do i need to do any extra step to make it work.
this is a default behaviour.
when your value = '' and you press delete it is still equal to '' and onChanged not getting called.
to achieve your goals you should use a listener like RawKeyboardListener
Thanks to Vladyslav Ulianytskyi suggestion.
I have done this with the use of RawKEyboardListner. Here is the sample code.
RawKeyboardListener(
autofocus: true,
onKey: (event) {
setState(() {
if (event.isKeyPressed(LogicalKeyboardKey.backspace)) {
print("Perform Your Action");
}
});
},
focusNode: FocusNode(),
child: TextFormField(controller: bullet2Controller,
focusNode: focusNode2,
maxLines: null,
minLines: 1,
textCapitalization: TextCapitalization.sentences,
cursorColor: Colors.black,
showCursor: true,
autofocus: true,
textAlign: TextAlign.start,
inputFormatters: [LengthLimitingTextInputFormatter(140),
],
decoration: const InputDecoration(
disabledBorder: InputBorder.none,
border: InputBorder.none,
filled: true,
fillColor: Colors.white,
),
keyboardType: TextInputType.multiline,
textInputAction: TextInputAction.done,
),
),
)
You can try it will below code hope it's work for you
TextEditingController bullet2Controller = TextEditingController();
int currentTextLength = 0;
TextFormField(
maxLines: null,
controller: bullet2Controller,
decoration: InputDecoration(
hintText: 'Type your observations'
),
style: TextStyle(
fontSize: 14,
fontWeight: FontWeight.w300,
fontFamily: 'Roboto'
),
onChanged: (String newText){
if (newText != ''){
if(newText[0] != '•'){
newText = '• ' + newText;
bullet2Controller.text = newText;
bullet2Controller.selection = TextSelection.fromPosition(TextPosition(offset: bullet2Controller.text.length));
}
if(newText[newText.length - 1] == '\n' && newText.length > currentTextLength){
bullet2Controller.text = newText + '• ';
bullet2Controller.selection = TextSelection.fromPosition(TextPosition(offset: bullet2Controller.text.length));
}
currentTextLength = bullet2Controller.text.length;
}
}
)
let me know if it's work for you or let me know if there any question.
I have a TextFormField with borders. I am using a validator with some conditions to show proper error messages. My error messages are shown exactly below the TextFormField border which is what I want. In my validator, I use an if statement that should return a String, so I have to add return '' after the if statement, as shown in my code:
TextFormField buildPasswordForm() {
return TextFormField(
//key: ValueKey('passwordKey'),
keyboardType: TextInputType.visiblePassword,
obscureText: _isHidden,
decoration: InputDecoration(
//labelText: 'Passowrd',
hintText: 'Password',
floatingLabelBehavior: FloatingLabelBehavior.never,
prefixIcon: Icon(
Icons.lock_sharp,
//color: kTextColor,
),
suffixIcon: Padding(
padding: EdgeInsets.symmetric(
horizontal: getProportionateScreenWidth(12),
),
child: GestureDetector(
onTapDown: inContact,
onTapUp: outContact,
child: Icon(
Icons.remove_red_eye,
size: 26,
//color: kTextColor,
),
),
),
),
validator: (value) {
if (value.isEmpty) {
addPasswordError(error: kPasswordNullError);
return '';
} else if (value.length < 8) {
addPasswordError(error: kShortPasswordError);
return '';
}
return null;
},
onChanged: (value) {
if (value.isNotEmpty) {
removePasswordError(error: kPasswordNullError);
} else if (value.length >= 8) {
removePasswordError(error: kShortPasswordError);
}
return null;
},
onSaved: (newValue) => password = newValue,
);
}
TextFormField buildEmailForm() {
return TextFormField(
keyboardType: TextInputType.emailAddress,
//autofocus: true,
decoration: InputDecoration(
//labelText: 'Email',
hintText: 'Enter your email',
floatingLabelBehavior: FloatingLabelBehavior.always,
prefixIcon: Icon(Icons.mail),
),
validator: (value) {
if (value.isEmpty) {
addEmailError(error: kEmailNullError);
return "";
} else if (!emailValidatorRegExp.hasMatch(value)) {
addEmailError(error: kInvalidEmailError);
return "";
}
return null;
},
onChanged: (value) {
if (value.isNotEmpty) {
removeEmailError(error: kEmailNullError);
} else if (emailValidatorRegExp.hasMatch(value)) {
emailErrors.remove(kInvalidEmailError);
addEmailError(error: kInvalidEmailError);
}
return null;
},
onSaved: (newValue) => email = newValue,
);
}
}
If I add return '', the space between the error message and the bottom board is added, but if the validation is not satisfied, that is: if neither email nor password entered satisfy requirements, the screen does not go to the next one as it should. If I remove return '', then the space between the error message and the bottom borders disappears, but when I hit continue, wether fields are properly filled or not, the screen just goes to the next one.
I would love to have a solution for, and explanation of this behavior.
in my case is like this i usually separate my validator to a different class
class Validator{
static String email(String value){
String pattern = r'^[a-zA-Z0-9.]+#[a-zA-Z0-9]+\.[a-zA-Z]';
RegExp regExp = RegExp(pattern);
if(!regExp.hasMatch(value)) return 'Email is invalid';
else if(value.isEmpty) return 'Email is Empty';
else return null;
}
}
then i create a widget for my textformfield and to call the validator like this
CustomTextFieldX(
obsecure: false,
hintText: 'Enter your email',
nameTop: 'Email',
controller: registerController.emails,
keyboardType: TextInputType.emailAddress,
validators: (value) =>Validator.email(registerController.emails.text = value),
),
i hope it helps. just comment below if their something to clarify at.
I have a login page but I only want the form to accept emails with a specific domain (e.g. #abc.net). Here is the code I have so far. How would I implement this?
Widget _showEmailInput() {
return new Padding(
padding: EdgeInsets.fromLTRB(15.0, 15.0, 15.0, 0.0),
child: TextFormField(
maxLines: 1,
keyboardType: TextInputType.emailAddress,
autofocus: false,
decoration: new InputDecoration(
hintText: 'Enter Email', icon: Icon(Icons.email, color: black)),
validator: (value) => value.isEmpty ? 'Email can not be empty' : null,
onSaved: (value) => _email = value.trim(),
));
}
Method 1
var isValid = value.toLowerCase().endsWith('your_domain.com');
Method 2 (RegEx)
validator: (value) {
if (value.isEmpty) return 'Email can not be empty'
var rx = RegExp("\b*#abc\.net\$",caseSensitive: false);
return rx.hasMatch(value) ? null : 'Invalid domain name';
}
Just replace abc.net to your desired domain name
print(rx.hasMatch('sdfsdf#sdf.net')); // false
print(rx.hasMatch('sdfsdf#abc.net')); // true
print(rx.hasMatch('sdfsdf#ABC.org')); // false
print(rx.hasMatch('sdfsdf#ABc.net')); // true
I have a text field that allows only digits. But when my user adds a new model then I need to preassign a value to the field numberOfPets.
Only 0-9 is allowed so I could use 0 but I would rather have an empty string in that text field but that is not possible as String is not a subtype of Int... I have also tried null but that is literally written as initialValue.
How would you display an empty string in that textfield ?
TextFormField(
keyboardType: TextInputType.number,
inputFormatters: [
LengthLimitingTextInputFormatter(3),
WhitelistingTextInputFormatter.digitsOnly,
],
decoration: const InputDecoration(
labelText: 'reps',
),
initialValue: widget.set.numberOfPets.toString() ,
validator: (value) {
return StringFieldValidator.validate(value);
},
onChanged: (value) {
setState(() {
widget.set.numberOfPets= int.parse(value);
});
},
),
Keep the numberOfPets as 0 but while assigning to initialValue check if 0 and change it to empty string
TextFormField(
keyboardType: TextInputType.number,
inputFormatters: [
LengthLimitingTextInputFormatter(3),
WhitelistingTextInputFormatter.digitsOnly,
],
decoration: const InputDecoration(
labelText: 'reps',
),
initialValue: widget.set.numberOfPets ==0 ? '' : widget.set.numberOfPets.toString() ,
validator: (value) {
return StringFieldValidator.validate(value);
},
onChanged: (value) {
setState(() {
widget.set.numberOfPets= int.parse(value);
});
},
),