Home > Net >  In flutter, how to custom style error messages for textformfield?
In flutter, how to custom style error messages for textformfield?

Time:02-28

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.

Bloated textformfield with wrapping 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),
        )),
  ],
);
  • Related