First, Recently I have started to building desktop app with dart code.
just built some screens and which are responsible for mobile and web too, for that used LayoutBuilder
but going wrong with when trying to set the height according to mine, for that I wrapped TextformField with Container and gave height.
when I put validation on TextformField onClick of login button then something goes wrong with the height of TextformField.
Look at the Screenshot:
before of click the login button:
When I click the login button without inputting any value for checking validation:
Piece of code of TextformField :
Widget _buildEmailTextField() {
return Container(
height: 35,
child: Theme(
data: new ThemeData(
primaryColor: Color(0xFF262C48),
primaryColorDark: Color(0xFF262C48),
),
child: TextFormField(
keyboardType: TextInputType.emailAddress,
validator: (val){
bool emailValid = RegExp(r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+#[a-zA-Z0-9]+\.[a-zA-Z]+")
.hasMatch(val);
if(!emailValid){
return 'Invalid Email Address';
}else{
return null;
}
},
controller: emailController,
readOnly: isLoading?true:false,
decoration: InputDecoration(
fillColor: Color(0xFFd9d8d8),
filled: true,
border: new OutlineInputBorder(
borderRadius: const BorderRadius.all(
const Radius.circular(7.0),
),
borderSide: BorderSide(color:Color(0xFF262C48),width: 2.0)
),
contentPadding: EdgeInsets.only(left: 10),
// prefixIcon: Icon(
// Icons.email,
// color: Color(0xFF008577),
// ),
hintText: 'Email',
),
),
),
);
}
TextFormField inherits size from child. One of solution is to set contentPadding in InputDecoration.
You already use this to pad left side. You can do modification like below:
contentPadding: EdgeInsets.only(left: 10.0, top: 15.0, bottom: 15.0),
Please check it out,
Widget _buildEmailTextField()) {
return Container(
height: 35,
child: Theme(
data: new ThemeData(
primaryColor: Color(0xFF262C48),
primaryColorDark: Color(0xFF262C48),
),
child: Form(
key: _formKey,
child: Column(
children: [
SizedBox(
height: 20,
),
Container(
child: TextFormField(
keyboardType: TextInputType.emailAddress,
validator: (val) {
bool emailValid = RegExp(
r"^[a-zA-Z0-9.a-zA-Z0-9.!#$%&'*+-/=?^_`{|}~]+#[a-zA-Z0-9]+\.[a-zA-Z]+")
.hasMatch(val);
if (!emailValid) {
return 'Invalid Email Address';
} else {
return null;
}
},
controller: emailController,
readOnly: isLoading ? true : false,
decoration: InputDecoration(
fillColor: Color(0xFFd9d8d8),
filled: true,
border: new OutlineInputBorder(
borderRadius: const BorderRadius.all(
const Radius.circular(7.0),
),
borderSide:
BorderSide(color: Color(0xFF262C48), width: 2.0)),
contentPadding: new EdgeInsets.symmetric(
vertical: 25.0, horizontal: 10.0),
// prefixIcon: Icon(
// Icons.email,
// color: Color(0xFF008577),
// ),
hintText: 'Email',
),
),
),
RaisedButton(
onPressed: () {
// Validate returns true if the form is valid, otherwise false.
if (_formKey.currentState.validate()) {
// If the form is valid, display a snackbar. In the real world,
// you'd often call a server or save the information in a database.
Scaffold.of(context).showSnackBar(
SnackBar(content: Text('Processing Data')));
}
},
child: Text('Submit'),
)
],
),
),
),
);
}
Related
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(),
],
)),
)
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]')),
],
),
),
);
}
I've often seen where fields are responsive when users are typing, giving realtime feedback. An example is when I'm typing confirm password or email, if the confirm password or email hasn't matched the password while typing it returns error by marking turning the border of the field red until it matches the correct input. I have written this code, how do I improve the code to be responsive as described.
Widget _buildConfirmPasswordTF() {
return Column(crossAxisAlignment: CrossAxisAlignment.start, children: <Widget>[
// Text('Password', style: kLabelStyle,),
SizedBox(height: 10.0),
Container(alignment: Alignment.centerLeft, decoration: kBoxDecorationStyle, height: 60.0, child: TextFormField(
validator: ( confirmPassword ){
if ( confirmPassword.trim() != _password.isValidPassword ) {
return null;
} else {
return 'Password doesn\'t match';
}
},
obscureText: true, style: TextStyle(color: Colors.white, fontFamily: 'OpenSans',),
decoration: InputDecoration(border: InputBorder.none, contentPadding: EdgeInsets.only(top: 14.0),
prefixIcon: Icon(Icons.lock, color: Colors.white,),
hintText: 'Enter Confirm Password',
hintStyle: kHintTextStyle,
errorBorder: OutlineInputBorder( borderSide: BorderSide( color: Colors.red ) ),
focusedErrorBorder: OutlineInputBorder( borderSide: BorderSide( color: Colors.red ) )
),
),
),
],
);
}
This is where I set the hintText
final kHintTextStyle = TextStyle(
color: Colors.white54,
fontFamily: 'OpenSans',
);
This is where I set the labelStyle
final kLabelStyle = TextStyle(
color: Colors.white,
fontWeight: FontWeight.bold,
fontFamily: 'OpenSans',
);
This is where I set the border decoration
final kBoxDecorationStyle = BoxDecoration(
color: Color(0xFF6CA8F1),
borderRadius: BorderRadius.circular(10.0),
boxShadow: [
BoxShadow(
color: Colors.black12,
blurRadius: 6.0,
offset: Offset(0, 2),
),
],
);
you need autovalidateMode: AutovalidateMode.onUserInteraction, pass this in textformfield.
You can do that with a Form() providing it a key and a autoValidateMode to make sure the fields have value or that the value is something you except, you can add another field to confirm the passwork or email and compare the value of the field in the onChanged with the value of the other email field to make sure they match.
import 'package:email_validator/email_validator.dart';
final formKey = GlobalKey<FormState>();
final _emailController = TextEditingController();
final _passwordController = TextEditingController();
bool isValid = false;
_emailController.addListener(
() {
//With this, you can "listen" all the changes on your text while
//you are typing on input
//use setState to rebuild the widget
if (EmailValidator.validate(_emailController.text)) {
setState(() {
isValid = true;
});
} else {
setState(() {
isValid = false;
});
}
},
);
Form(
key: formKey,
autovalidateMode: AutovalidateMode.onUserInteraction,
child: Column(
children: [
Padding(
padding: EdgeInsets.symmetric(
horizontal: size.width * 0.105),
child: TextFormField(
validator: (value) =>
!EmailValidator.validate(value)
? 'Enter a valid email'
: null,
keyboardType: TextInputType.emailAddress,
textAlign: TextAlign.center,
controller: _emailController,
decoration: kInputDecoration.copyWith(
hintText: 'Enter your email'),
),
),
SizedBox(
height: 18,
),
Padding(
padding: EdgeInsets.symmetric(
horizontal: size.width * 0.105),
child: TextFormField(
obscureText: true,
validator: (value) =>
value.isEmpty ? 'Enter your password' : null,
keyboardType: TextInputType.text,
textAlign: TextAlign.center,
controller: _passwordController,
decoration: kInputDecoration.copyWith(
hintText: 'Enter your password'),
),
),
],
),
),
How to validate same field for either email or phone or not null??
TextFormField(
// validator: ???,
decoration: InputDecoration(
contentPadding: const EdgeInsets.all(16.0),
hintText: "hint_phone_no_email_address",
filled: true,
fillColor: Colors.grey.withOpacity(0.1),
),
),
I want to validate when I press my button
RaisedButton(
onPressed: () {
// call validate function from here.....
},
textColor: Colors.white,
padding: const EdgeInsets.all(0.0),
child: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: <Color>[
Color(0xFF0D47A1),
Color(0xFF1976D2),
Color(0xFF42A5F5),
],
),
),
child:
Text('Next', style: TextStyle(fontSize: 20)),
),
),
Please let me know...
1. Define Validation methods
Here I use email_validator for verifying the emails and a Regular Expression for the phone numbers. You can either also check intl_phone_field for the phone numbers, or libphonenumber (Though, not yet supported for Web or Desktop):
bool isEmail(String input) => EmailValidator.validate(input);
bool isPhone(String input) => RegExp(
r'^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$'
).hasMatch(input);
2. Define your TextFormField
Then, in your TextFormField, define a GlobalKey<FormFieldState> and a validator where you test for both emails and phone numbers:
TextFormField(
key: _key.value,
validator: (value) {
if (!isEmail(value) && !isPhone(value)) {
return 'Please enter a valid email or phone number.';
}
return null;
},
decoration: InputDecoration(
contentPadding: const EdgeInsets.all(16.0),
hintText: "Enter your phone number or email",
filled: true,
fillColor: Colors.grey.withOpacity(0.1),
),
),
3. Validate the TextFormField on button press
When the user press the button, validate the TextFormField and navigate if valid.
ElevatedButton(
onPressed: () {
if (_key.value.currentState.validate()) {
// Navigate to next page
}
},
style: ButtonStyle(
padding: MaterialStateProperty.all(const EdgeInsets.all(0.0)),
foregroundColor: MaterialStateProperty.all(Colors.white),
backgroundColor: MaterialStateProperty.all(Color(0xFF0D47A1))
),
child: Text('Next', style: TextStyle(fontSize: 20)),
),
Full source code
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:email_validator/email_validator.dart';
void main() {
runApp(
MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
home: HomePage(),
),
);
}
bool isEmail(String input) => EmailValidator.validate(input);
bool isPhone(String input) =>
RegExp(r'^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$')
.hasMatch(input);
class HomePage extends HookWidget {
#override
Widget build(BuildContext context) {
final _key = useState(GlobalKey<FormFieldState>());
return Scaffold(
body: Container(
alignment: Alignment.center,
padding: EdgeInsets.all(16.0),
child: Column(
children: [
TextFormField(
key: _key.value,
validator: (value) {
if (!isEmail(value) && !isPhone(value)) {
return 'Please enter a valid email or phone number.';
}
return null;
},
decoration: InputDecoration(
contentPadding: const EdgeInsets.all(16.0),
hintText: "Enter your phone number or email",
filled: true,
fillColor: Colors.grey.withOpacity(0.1),
),
),
const SizedBox(height: 16.0),
ElevatedButton(
onPressed: () {
if (_key.value.currentState.validate()) {
// Navigate to next page
}
},
style: ButtonStyle(
padding: MaterialStateProperty.all(const EdgeInsets.all(0.0)),
foregroundColor: MaterialStateProperty.all(Colors.white),
backgroundColor:
MaterialStateProperty.all(Color(0xFF0D47A1))),
child: Text('Next', style: TextStyle(fontSize: 20)),
),
],
),
),
);
}
}
Wrap the textFormFields with a Form
Give the Form a key and create this key [_formKey] in initState
Create validator for each TextFormField that needs to be validated when your button is pressed.
Call _formKey.currentState.validate() which returns true if and only if ALL fields are validated otherwise false.
class _SomeClassState extends State<SomeClass>{
GlobalKey<FormState> _formKey; // DECLARE a formKey
#override
void initState(){
super.initState();
_formKey = GlobalKey(); // INSTANTIATE the key here
...
}
/// 4. validate function
void validateController(){
if(!_formKey.currentState.validate()){
// value is false.. textFields are rebuilt in order to show errorLabels
return;
}
// action WHEN values are valid
}
#override
Widget build(BuildContext context){
return Scaffold(
...
// 1. Form should be at the top of the widget tree
Form(
key: _formKey, // 2.
child:
...
TextFormField(
validator:(string) => string.isEmpty // 3. add your validating function here
decoration: InputDecoration(
contentPadding: const EdgeInsets.all(16.0),
hintText: "hint_phone_no_email_address",
filled: true,
fillColor: Colors.grey.withOpacity(0.1),
),
),
...
...
RaisedButton(
onPressed: validateControllers, //4. calls function that validates [when button is pressed ONLY]
textColor: Colors.white,
padding: const EdgeInsets.all(0.0),
child: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: <Color>[
Color(0xFF0D47A1),
Color(0xFF1976D2),
Color(0xFF42A5F5),
],
),
),
child: Text('Next', style: TextStyle(fontSize: 20)),
),
),
...
For section 3, where you plan to create a validator for either 'Email' or 'Phone number', you can use RegExp.
if you want to validate many fields, it is advisable to use the Form widget
first make a form key
final GlobalKey<FormState> formKey = GlobalKey<FormState>();
Form(
key: formKey,
child: Column(
children: <Widget>[
TextFormField(
validator: (String value) {
if (value.isEmpty) {
return 'Email is Required';
}
if (!RegExp(
r"^([a-zA-Z0-9_\-\.]+)#([a-zA-Z0-9_\-\.]+)\.([a-zA-Z]{2,5})$")
.hasMatch(value)) {
return 'Please enter a valid Email';
}
return null;
},
decoration: InputDecoration(
contentPadding: const EdgeInsets.all(16.0),
hintText: "hint_phone_no_email_address",
filled: true,
fillColor: Colors.grey.withOpacity(0.1),
),
),
//validating when the raised button is pressed
RaisedButton(
onPressed: () {
// call validate function from here.....
validateEmail(),
},
textColor: Colors.white,
padding: const EdgeInsets.all(0.0),
child: Container(
decoration: const BoxDecoration(
gradient: LinearGradient(
colors: <Color>[
Color(0xFF0D47A1),
Color(0xFF1976D2),
Color(0xFF42A5F5),
],
),
),
child:
Text('Next', style: TextStyle(fontSize: 20)),
),
),
validateEmail()async{
FormState form = formKey.currentState;
form.save();
if (!form.validate()) {
print('Invalid Email');
}else{
print('Credentials are valid');
}
}
When the error message shows up, it reduces the height of the TextFormField. If I understood correctly, that's because the height of the error message is taking into account in the height specified.
Here's a screen before :
and after :
Tried to put conterText: ' ' to the BoxDecoration (as I've seen on another topic) but it didn't help.
An idea ?
EDIT : OMG completly forgot to put the code, here it is :
return Form(
key: _formKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Container(
height: 40.0,
child: _createTextFormField(loginEmailController, Icons.alternate_email, "Email Adress", false, TextInputType.emailAddress),
),
Container(
height: 40.0,
child: _createTextFormField(loginPasswordController, Icons.lock, "Password", true, TextInputType.text),
),
SizedBox(
width: double.infinity,
child: loginButton
)
],
),
);
}
Widget _createTextFormField(TextEditingController controller, IconData icon, String hintText, bool obscureText, TextInputType inputType){
return TextFormField(
keyboardType: inputType,
controller: controller,
obscureText: obscureText,
/* style: TextStyle(
fontSize: 15.0,
), */
decoration: InputDecoration(
/* contentPadding:
EdgeInsets.symmetric(vertical: 5.0, horizontal: 8.0), */
border: OutlineInputBorder(borderRadius: BorderRadius.circular(5.0)),
icon: Icon(
icon,
color: Colors.black,
size: 22.0,
),
//hintText: hintText,
labelText: hintText,
),
validator: (value) {
if (value.isEmpty) {
return 'Enter some text';
}
return null;
},
);
}
In your Code - you need to comment out the 40 height given to each container.
Container(
// height: 40.0,
child: _createTextFormField(
loginEmailController,
Icons.alternate_email,
"Email Adress",
false,
TextInputType.emailAddress),
),
Container(
// height: 40.0,
child: _createTextFormField(loginPasswordController, Icons.lock,
"Password", true, TextInputType.text),
),
and then in your - TextFormField in InputDecoration, you can alter these value as per your liking.
contentPadding:
EdgeInsets.symmetric(vertical: 10.0, horizontal: 10.0),
Above solutions did not work for me however I have figured out a very simple solution to avoid the above issue
TextFormField(
decoration: InputDecoration(
**errorStyle: const TextStyle(fontSize: 0.01),**
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(borderRadius),
borderSide: const BorderSide(
color: AppColor.neonRed,
width: LayoutConstants.dimen_1,
style: BorderStyle.solid,
),
),
);
Catch in the above solution is that we are setting the size of the error message to 0.01 so as a result it don't show up.
Additionally we can have custom border for the error.
Note : Setting the Text size to 0 is not working as it don't consider the text size and textFormField widget gets shrinked.
The problem is that we are not able to see your code so it might be challenging to assist you but I will do everything from scratch. You can firstly create the authentication class in one dart file
class AuthBloc{
StreamController _passController = new StreamController();
Stream get passStream => _passController.stream;
bool isValid(String pass){
_passController.sink.add("");
if(pass == null || pass.length < 6){
_passController.sink.addError("Password is too short");
return false;
}
else{
return true;
}
}
void dispose(){
_passController.close();
}
}
And then insert the following code in another dart file...
class LoginPage extends StatefulWidget{
#override
_LoginPageState createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage>{
AuthBloc authBloc = new AuthBloc();
#override
void dispose(){
authBloc.dispose();
}
#override
Widget build(BuildContext context){
return Scaffold(
body: Container(
padding: EdgeInsets.fromLTRB(30, 0, 30, 0),
constraints: BoxConstraints.expand(),
children: <Widget>[
Padding(
padding: const EdgeInsets.fromLTRB(0, 40, 0, 20),
child: StreamBuilder(
stream: authBloc.passStream,
builder: (context, snapshot) => TextField(
controller: _passController,
style: TextStyle(fontSize: 18, color: Colors.black),
decoration: InputDecoration(
errorText: snapshot.hasError ? snapshot.error:null,
labelText: "Password",
prefixIcon: Container(
width: 50,
child: Icon(Icons.lock),
),
border: OutlineInputBorder(
borderSide: BorderSide(color: Color(0xffCED802), width: 1),
borderRadius: BorderRadius.all(Radius.circular(6))
)
),
),
)
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 30, 0, 40),
child: SizedBox(
width: double.infinity,
height: 52,
child: RaisedButton(
onPressed: _onLoginClicked,
child: Text(
"Login",
style: TextStyle(fontSize: 18, color: Colors.white),
),
color: Color(0xff327708),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(6))
),
),
),
),
]
)
)
}
_onLoginClicked(){
var isValid = authBloc.isValid(_passController.text);
if(isValid){
//insert your action
}
}
}
I hope it works :)
Instead of using a fixed height container to wrap the textFormField, You can try to put a space in the helper text so it will keep the height of the field constant while only displaying when there is an error.
return TextFormField(
// ...
decoration: InputDecoration(
// ...
helperText: " ",
helperStyle: <Your errorStyle>,
)
According to Flutter Doc :
To create a field whose height is fixed regardless of whether or not an error is displayed, either wrap the TextFormField in a fixed height parent like SizedBox, or set the InputDecoration.helperText parameter to a space.
The problem with content padding is that you cant decrease the size of the field to UI requirement with an emphasize on decrease but how ever the second answer helped me come with a solution for my perticular problem, so am sharing that
StreamBuilder(
stream: viewModel.outEmailError,
builder: (context, snap) {
return Container(
width: MediaQuery.of(context).size.width*.7,
height: (snap.hasData)?55:35,
child: AccountTextFormField(
"E-mail",
textInputType: TextInputType.emailAddress,
focusNode: viewModel.emailFocus,
controller: viewModel.emailController,
errorText: snap.data,
textCapitalization: TextCapitalization.none,
onFieldSubmitted: (_) {
nextFocus(viewModel.emailFocus,
viewModel.passwordFocus, context);
},
),
);
}),