My textformfield is styled in a way that is wrapped with a grey wrapping container to look differently when the field is in-focus. However, it becomes bloated (increases in size) whenever there is an error message because the field is wrapped with that grey wrapping container.
How do I custom style the error message outside of the grey wrapping container so that the textformfield doesn't bloat in size?
Essentially I want the error message to be positioned outside of grey the wrapper container.
@override Widget build(BuildContext context) {
final InputDecorationTheme inputTheme = Theme.of(context).inputDecorationTheme;
return Focus(
canRequestFocus: false,
child: Builder(builder: (context) {
final FocusNode focusNode = Focus.of(context);
final bool hasFocus = focusNode.hasFocus;
return GestureDetector(
onTap: () {
if (hasFocus) {
focusNode.unfocus();
} else {
focusNode.requestFocus();
}
},
child: Container(
decoration: BoxDecoration(
color: hasFocus ? Colors.white : Color(0xFFF4F4F4),
border: hasFocus
? Border.all(color: Color(0xFF0E4DA4), width: 2)
: Border.all(width: 2, color: Colors.transparent),
borderRadius: const BorderRadius.all(Radius.circular(5)),
boxShadow: hasFocus
? [
BoxShadow(
color: Color(0xFFF4F4F4),
spreadRadius: 3,
blurRadius: 0,
offset: Offset(0, 0), // changes position of shadow
),
]
: [],
),
child: TextFormField(
enabled: enabled,
key: this.customKey,
controller: textEditingController,
initialValue: initialValue,
inputFormatters: isNumericalOnly
? [
FilteringTextInputFormatter.digitsOnly,
FilteringTextInputFormatter.singleLineFormatter,
]
: [
FilteringTextInputFormatter.singleLineFormatter,
],
keyboardType: isNumericalOnly ? TextInputType.number : TextInputType.text,
focusNode: focusNodeToggle,
maxLength: maxLength,
validator: (String? value) {
return validator != null ? validator!(value.toString()) : null;
},
onSaved: (String? value) {
return onSaved != null ? onSaved!(value.toString()) : null;
},
onChanged: (String? value) {
return onChanged != null ? onChanged!(value.toString()) : null;
},
buildCounter: maxLength != null && isCounterVisible == true
? (BuildContext context, {int? currentLength, int? maxLength, bool? isFocused}) =>
Container(child: Text('$currentLength/$maxLength'))
: (BuildContext context, {int? currentLength, int? maxLength, bool? isFocused}) =>
null,
decoration: InputDecoration(
floatingLabelBehavior: FloatingLabelBehavior.auto,
hintText: customHintText,
helperText: customHelperText,
helperMaxLines: 2,
filled: true,
fillColor: Colors.transparent,
border: InputBorder.none,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
disabledBorder: InputBorder.none,
labelStyle: hasFocus ? inputTheme.labelStyle : TextStyle(color: Color(0xFF525252)),
label: Text.rich(
TextSpan(
children: <InlineSpan>[
WidgetSpan(
child: Text(
label.toString(),
),
),
WidgetSpan(
child: isDataloading
? LoadingIndicator(
width: 15,
height: 15,
)
: Text('')),
],
),
),
),
),
),
);
}),
);
}
CodePudding user response:
First you need to 1 String for each field
String nameError = '';
Now you need to create validation function for this field like
void invalidName() {
nameError = "Enter name";
}
Now you need to create function where you can check all validation
bool validateInput() {
try {
if (email.isNotEmpty) {
return true;
} else {
if (nameController.text.isEmpty) { // Here check your controller value
invalidName(); // here define validation error
...
...
}
return false;
}
} catch (e) {
return false;
}
}
Now you just need to call validateInput() function in your button if its return true then call you api or something other wise shows error in below of textfield like below
nameError == '' ? SizedBox() : Text(nameError)
CodePudding user response:
You can do this by maintaining a column of a TextFormField and Text Widget(for showing error message). You can do something like this.
final FocusNode focusNode = Focus.of(context);
final bool hasFocus = focusNode.hasFocus;
Column(
children: [
Container(
margin: EdgeInsets.symmetric(horizontal: 20.0),
child: TextFormField(
focusNode: focusNode,
onFieldSubmitted: (v) {
FocusScope.of(context).requestFocus(focus);
},
textInputAction: TextInputAction.next,
controller: , //your controller
autofocus: false,
decoration: InputDecoration(
hintText: "sample text*",
errorStyle: TextStyle(color: Colors.red),
hintStyle: TextStyle(
fontSize: 20,
color: Colors.grey),
border: OutlineInputBorder(
borderRadius:
BorderRadius.circular(5),
borderSide: BorderSide(
//color: Colors.amber,
),
),
enabledBorder: OutlineInputBorder(
borderRadius:
BorderRadius.circular(5),
borderSide:
BorderSide(width: 1, color: Colors.black),
),
),
style: TextStyle(
fontSize: 20,
color: Colors.black,
),
),
),
SizedBox(
height: 5,
),
Visibility(
visible: hasFocus,
child: Text(
'Required field, it cannot be empty',
style: TextStyle(color: Color.red),
)),
],
);