Validator pushed TextFormField above - flutter

I tried creating an email textfield with validator using TextFormField. Since the textfield height is too much for my liking, I wrap the TextFormField with Container and set the height to 50. Now the problem is whenever I submitted intended wrong value, the validator will popped out and pushed the textfield, leaving the height much smaller than what I set in Container.
Before submitting:
After submitting:
Here is my codes:
Widget _emailForm() {
return Form(
key: _emailFormKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text("Enter Your Email", style: TextStyle(fontSize: 13.0, fontWeight: FontWeight.bold),),
Padding(padding: EdgeInsets.symmetric(vertical: 4.0),),
Container(
height: 50,
child: TextFormField(
focusNode: _emailFocusNode,
style: TextStyle(fontSize: 11.0, fontWeight: FontWeight.w600),
keyboardType: TextInputType.emailAddress,
controller: _emailTextController,
decoration: InputDecoration(
isDense: true,
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.all(Radius.circular(0.0),),
),
suffixIcon: IconButton(
alignment: Alignment.centerRight,
iconSize: 16.0,
icon: Icon(Icons.clear),
onPressed: () {
if(_emailTextController != null) {
_emailTextController.clear();
FocusScope.of(context).requestFocus(_emailFocusNode);
}
},
),
border: OutlineInputBorder(
borderRadius: BorderRadius.all(
Radius.circular(0.0),
),
borderSide: BorderSide(
color: Colors.black,
width: 1.0
)
),
errorStyle: _errorTextStyle,
),
validator: (val) {
Pattern pattern = r'#';
RegExp regex = RegExp(pattern);
if(val.isEmpty) return "* Email address can't be empty";
else if(!regex.hasMatch(val)) return "* Invalid email address";
else {
return null;
}
},
),
),
Padding(padding: EdgeInsets.symmetric(vertical: 6.0),),
FlatButton(
child: Text("Join".toUpperCase(), style: TextStyle(color: Colors.white, fontSize: 11),),
onPressed: (){
if(_emailFormKey.currentState.validate()) {
_joinWaitingList();
}
},
color: _themeColor,
),
],
),
);
}
This widget is part of ListView in my build method if that information is helping. Is there any way to solve this problem? Thanks!

The problem is that TextField and TextFormField size themselves to include all of their content and decoration. If you add some error text onto the bottom of the TextFormField, then it will include that in its height. When it tries to size itself to fit into your Container, it doesn't have as much space for the input.
You could work around this by specifying the height of your Container in both the valid and invalid states. You'll have to fiddle with the exact invalid height, but it might look something like this:
Container(
height: _isInvalid ? 100 : 50,
TextFormField(),
),
Another option is to add counterText: ' ' to your InputDecoration and then size the Container to the size that you want. This will give you extra space to fit the error text without needing to change the height of the TextFormField.
Container(
height: 100,
TextFormField(
decoration: InputDecoration(
counterText: ' ',
),
),
),
The cleanest solution, if it's possible for you, may be to not use a Container at all. If you can create the input you want just by using InputDecoration and things like contentPadding etc., it will likely make this a lot cleaner.

hey i think that its works if u use onchanged instead of validator :
onChanged: (val) {
Pattern pattern = r'#';
RegExp regex = RegExp(pattern);
if(val.isEmpty) return "* Email address can't be empty";
else if(!regex.hasMatch(val)) return "* Invalid email address";
else {
return null;
}
},

Related

Why is there whitespace when I add a SizedBox to a Textfield?

I have been trying to adjust the size of the text field but whenever I do it I have a lot of whitespace. Whenever I add a SizedBox it starts to add lots of whitespace. I have the TextField embedded in a MaterialApp and a Scaffold. So I am stuck on this.
This is without the SizedBox:
TextField(
decoration: InputDecoration(
hintText: "Enter Your Email Address",
border: OutlineInputBorder(),
contentPadding: EdgeInsets.all(30),
),
),
This is when you add the SizedBox:
SizedBox(
height: 100,
width: 100,
child: TextField(
decoration: InputDecoration(
hintText: "Enter Your Email Address",
border: OutlineInputBorder(),
contentPadding: EdgeInsets.all(30),
),
),
),
When there is no SizedBox
When the SizedBox is added
Probably you are not using Column, that's why when you wrap your TextField with SizedBox the screen takes SizedBox's width. At the top in body of Scaffold you should use Column.\
If you already have Column, please share your whole code for this particular page, and let me have a better look.
you can do like this.
Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: 45,
padding: EdgeInsets.fromLTRB(30, 0, 30, 0),
child: TextField(
textAlign: TextAlign.center,
textAlignVertical: TextAlignVertical.center,
decoration: InputDecoration(
hintText: "Enter Your Email Address",
border: OutlineInputBorder(),
contentPadding: EdgeInsets.all(30),
),
),
),]
),
Currently, the width of the widget tree is the width of the widget whose width is maximum(Here, the width of the widget tree is equal to the width of the next button).
set width of sizedBox to double.inifinity, it makes the sizedbox to occupy the available width i.e screen width.
And the widget tree occupies the entire width.
SizedBox(
height: 100,
width: double.infinity,
child: TextField(
decoration: InputDecoration(
hintText: "Enter Your Email Address",
border: OutlineInputBorder(),
contentPadding: EdgeInsets.all(30),
),
),
)
Please accept the solution if solves your problem
contentPadding: EdgeInsets.all(3),
just change this -> dont need to use SizedBox widget
You are adding a sized box which have 100 width and also 100 height ,so the sized box will be a squared box .
By increasing the width of the sized box like 300 something you can easily do this or I suggest you a way that a text field will be easily fixed in you code .
I hope this code will help you
Flexible(
child: TextFormField(
controller: _controller,
decoration: const InputDecoration(
labelText: 'Enter Something',
border: OutlineInputBorder(),
hintText: 'Enter Something ',
),
},
),
),
),
I generally used 'Sized Box' for spacing purpose in my flutter project
Use the below written code to understand how SizedBox works as spacing
class _sampleState extends State<sample> { #override Widget build(BuildContext context) {
return Scaffold(
body: Container(
alignment: Alignment.center,
child: Column(
children: [
SizedBox(height: 80,),
Text("Signup",style: TextStyle(fontSize: 30),),
SizedBox(height: 20,),
TextField(
decoration: InputDecoration(
// border: OutlineInputBorder(
// borderRadius: BorderRadius.circular(10.0),
// ),
filled: true,
hintStyle: TextStyle(color: Colors.white),
hintText: "Username or email",
fillColor: Color(0xff313F4D),
),
),
SizedBox(height: 50,),
ElevatedButton(onPressed: (){},
child: Text("Next"))
],
)),
);

How to add two or more icons to a textField?

I have a text field with a value. But I ran into a problem that I need to add icons next to the value in addition to the value. I can add one icon using suffixIcon. But I will need to add 3 icons, sometimes add 2 icons but I don't know how to add more than one icon to the text field?
Widget _defaultTextfield(
bool enabled,
TextInputType? type,
String hint,
String val,
BuildContext context,
) {
final MycarsCubit cubit = BlocProvider.of<MycarsCubit>(context);
return SizedBox(
height: 58,
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
color: constants.Colors.greyMiddle,
child: Row(
children: [
Flexible(
child: TextField(
style: constants.Styles.smallTextStyleWhite,
keyboardType: type,
controller: TextEditingController(text: '$val kW'),
onChanged: (value) {
cubit.change(
carModelNew: cubit.carModel,
idText: cubit.id,
modelText: cubit.model,
numberText: value,
typeText: cubit.type,
yearText: cubit.year,
chargeSpeedText: cubit.chargeSpeed,
connectorText: cubit.connector,
batteryCapacityText: cubit.batteryCapacity,
mainNew: cubit.main,
);
},
decoration: InputDecoration(
border: InputBorder.none,
enabled: enabled,
contentPadding: const EdgeInsets.all(8),
labelText: hint,
labelStyle: constants.Styles.textFieldLabelLightGreyStyle,
suffixIcon: const Icon(Icons.bolt),
suffixIconConstraints: BoxConstraints(
maxHeight: 10
)
),
),
),
],
),
),
);
}
You can do this:
TextField(
decoration: InputDecoration(
suffixIcon: Row(
children: [
Icon(Icons.bolt),
value == 10 ? Icon(Icons.bolt):SizedBox(),
],
)),
)

Change the error message position in Flutter

I have to make one application which take so many user input , that's why i use so many Textfiled in my code for taking user input.
An Textfiled validation time I simply use List of Global keys and it's work perfactly.
But problem is when user give wrong input then textfiled show an error message that time my Textbox UI can change (UI well change in very appropriately).
Pleas help , what can i do so my error message postion will be changed.
TextFiled code :
//this is inside the statfull Widget
GlobalKey<FormState> _formkeySubNumber = new GlobalKey();
Widget SubNumber_Input_Box() {
return Form(
//for form validation
key: _formkeySubNumber,
child: Container(
margin: EdgeInsets.only(top: 7, left: 6),
height: 38,
width: 300,
decoration: BoxDecoration(
color: HexColor("#D9D9D9"),
borderRadius: BorderRadius.all(Radius.circular(10)),
),
//padding
child: Padding(
padding: EdgeInsets.only(left: 12),
//textfiled
child: TextFormField(
//for validation
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please Enter Subject Number';
}
return null;
},
//for storing user input && value in string format so we convert into the int formate
onChanged: (value) {
subjectNumber = int.tryParse(value)!;
},
//for only number
keyboardType: TextInputType.number,
decoration: const InputDecoration(
hintText: "Enter Minimum-4 to Maximum-8 Subject",
hintStyle: TextStyle(
fontFamily: "RobotoSlab",
fontSize: 14,
),
//for remove underline from input filed
border: InputBorder.none,
),
//for store only integer value
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(RegExp(r'[0-9]')),
],
),
),
),
);
}
And this call inside the one Button Like that
[Container(
margin: EdgeInsets.only(top: 5),
child: ElevatedButton(
child: Text("Go"),
style: ElevatedButton.styleFrom(
primary: HexColor("#EE6C4D"),
//this colour set (opacity is low) when button is disable
onSurface: HexColor("#E0FBFC"),
),
//store user value -->subjectNumber
onPressed: isGoButtonActive
? () {
//for Form Validation
if (_formkeySubNumber.currentState!
.validate()) {
//this show the container after prerssed button
showContainer1();
}
setState(() {
// //this is for store subjectnumber value from user input
// subjectNumber =
// subNumber_Controller.text;
// print("Subject Number Is : $subjectNumber");
});
}
: null,
),
),]
You have created a container around the textfield with specific height. For styling a textfield you can use
TextField(
decoration: InputDecoration(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(10.0),
),
filled: true,
hintStyle: TextStyle(color: Colors.grey),
hintText: "Type in your text",
fillColor: Colors.white),
)
This way the error message appears below the textfield and outside the white area.
You can remove the height from Form> Container. And it will give you flexible height based on error state.
Widget SubNumber_Input_Box() {
return Form(
key: _formkeySubNumber,
child: Container(
width: 300,
color: HexColor("#D9D9D9"),
//padding
child: Padding(
padding: EdgeInsets.only(left: 12),
child: TextFormField(
autovalidateMode: AutovalidateMode.onUserInteraction, // you might like this as well
Also I will suggest to look at OutlineInputBorder
Widget SubNumber_Input_Box() {
return Form(
key: _formkeySubNumber,
child: Padding(
padding: EdgeInsets.only(left: 12),
child: TextFormField(
autovalidateMode: AutovalidateMode.onUserInteraction,
//for validation
validator: (value) {
if (value == null || value.isEmpty) {
return 'Please Enter Subject Number';
}
return null;
},
//for storing user input && value in string format so we convert into the int formate
onChanged: (value) {
subjectNumber = int.tryParse(value)!;
},
//for only number
keyboardType: TextInputType.number,
decoration: const InputDecoration(
hintText: "Enter Minimum-4 to Maximum-8 Subject",
hintStyle: TextStyle(
fontFamily: "RobotoSlab",
fontSize: 14,
),
enabledBorder: OutlineInputBorder(),
errorBorder: OutlineInputBorder(),
focusedBorder: OutlineInputBorder(),
border: OutlineInputBorder(),
),
//for store only integer value
inputFormatters: <TextInputFormatter>[
FilteringTextInputFormatter.allow(RegExp(r'[0-9]')),
],
),
),
);
}

Push data from TextFormField Flutter to Listview.builder Items when form field is validated

I have form field :
This form field will collect all the data from my client.
Each of these field is specific and I want push the entry of each of these field into a ListView.builder according to the name of the field.
For example the field " Alias" has to be push into the listview.builder that you can see above, and the others fields has to be push to another listview.builder in order to build an address book.
this is my code for listview.builder.
Please I accept suggestion how to to that thanks:
Container(
height: 1000,
child: ListView.builder(
shrinkWrap: true,
itemBuilder: (ctx, int) {
return Card(
color: Color(0xFF1f2032),
elevation: 15,
child: Container(
width: 60,
height: 60,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: <Widget>[
Card(
color: Color(0xfffeaf0d),
child: Container(
height: 40,
width: 40,
child: Icon(Icons.location_on,color: Colors.white,size: 25,)),
),
Text('User id № $int',style: TextStyle(color: Colors.white,fontWeight: FontWeight.bold),),
Text(userDestinationFullName,style: TextStyle(fontWeight: FontWeight.bold,color: Color(0xfffeaf0d),),),
Text(aliasName,style: TextStyle(color: Colors.lightGreenAccent),),
Icon(Icons.cancel,color: Colors.white,)
],
),
));
},
),
),
Ok
the list view is the code I posted above
in such listview I need to have the data that I retrieve from the formfield which the customer will fill up.
For example:
In the field "Alias" into the form customer will write " Home "
this "Home" has to be shown into the listview
Customer will also write as "Nome e Cognome" the full name of the for example "Mario Rossi", then Mario Rossi has to appear into the list view in a single row.
this is the screenshot of the list view.
https://ibb.co/LN2nVtk
as you can see the horizontal list where is + alias, Alias... has to be substitute with the written field that customer fill in the form
vertical ListView has rows with several text, each of these text is a field into the form, so each of these field has to be substitute with the written filled into the form
This is just a field to a form
for example Full name field once filled the content has to be push into the listview as shipmentFullName
Widget FullName() {
return TextFormField(
validator: (value) {
if (value.isEmpty) {
return 'Nome e Cognome obbligatorio';
}
return null;
},
keyboardType: TextInputType.text,
style: TextStyle(color: Color(0xFF1f2032), fontSize: 14),
decoration: InputDecoration(
fillColor: Color(0xfffeaf0d),
filled: true,
labelText: 'Nome e Cognome',
labelStyle: TextStyle(color: Color(0xFF1f2032)),
prefixIcon: Icon(
Icons.person_add,
color: Color(0xFF1f2032),
size: 17,
),
hintStyle: TextStyle(
color: Color(0xFF1f2032),
),
hintText: 'Nome e Cognome del Destinatario',
contentPadding: EdgeInsets.symmetric(vertical: 5, horizontal: 35.0),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(color: Color(0xFF1f2032), width: 1.5),
borderRadius: BorderRadius.circular(5),
),
),
);
}

How to pass retrieved text to textfield Flutter

I am using speech to text (speech_recognition ) plugin and retrieving text from voice but how can i put the text in to the search field (TextField) after retrieving text. So i want to retrieve data from voice and search it.
here is my code:
// Here is retrieved text inside container
Container(
child: Center(
child: Text(
(transcription.isEmpty)
? "Speak to Record"
: "Your text is \n\n$transcription",
textAlign: TextAlign.center,
style: TextStyle(color: Colors.pink, fontSize: 20),
),
),
),
// Here is my SearchField (TextField)
Padding(
padding: const EdgeInsets.all(20),
child: TextField(
onChanged: (text) {
_con.refreshSearch(text);
},
onSubmitted: (text) {
_con.saveSearch(text);
},
controller: _searchController,
autofocus: true,
decoration: InputDecoration(
contentPadding: EdgeInsets.all(12),
hintText: S.of(context).search_for_product,
hintStyle: Theme.of(context)
.textTheme
.caption
.merge(TextStyle(fontSize: 14)),
prefixIcon:
Icon(Icons.search, color: Theme.of(context).accentColor),
border: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).focusColor.withOpacity(0.1))),
focusedBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).focusColor.withOpacity(0.3))),
enabledBorder: OutlineInputBorder(
borderSide: BorderSide(
color: Theme.of(context).focusColor.withOpacity(0.1))),
suffixIcon: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.end,
children: [
InkWell(
onTap: scanBarcode,
child: Image.asset(
"assets/img/barcode.png",
height: 20,
color: Colors.deepOrangeAccent,
),
),
_buildVoiceInput(
onPressed: _speechRecognitionAvailable && !_isListening
? () => start()
: () => stop(),
label: _isListening ? S.of(context).listening : '',
),
],
),
),
),
),
Taking the transcription value into consideration, which is responsible of having the text, what you can do is to make use of it, and change the data using Search TextEditingController.
So, here what I am taking about. I am not sure where are you fetching the data actually, but you can change the values, as soon as you get the data from the voice like this, and assign it to the Controller to fill the Search Field
// Suppose you are fetching the data from this method,
void fetchTextFromVoice(){
setState(() {
// Here you might be assigning the value to the Transcript value
this.transcription = data_from_voice;
// also this does the magic, which will put the data inside the Search Field
// Your TextEditingController is the key to do that
_searchController.text = data_from_voice;
// or _searchController.text = transcription; Since transcript has some value
});
}
Also, read about TextEditingController Class on what all are the operations you can perform using it. More knowledge to you on this Class will help you in great extent :)
I hope that helps, if not, then please show me where is the function where you are setting the value to transcription. You can assign the value to the same place, like above to _searchController.text and you are good to go. Let me know :)