Search code examples
flutterflutter-layouttextformfield

Flutter : change bordercolor after validation


I want to change the borderColor of the TextFormField to a green color on successfull validation. The color should not fade on losing focus though. Is there something like successBorder similar to error/focusedBorder.

class FormLayout extends StatelessWidget {
  FormLayout({Key? key}) : super(key: key);

  final _nameController = TextEditingController();
  final _ageController = TextEditingController();

  final _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: const EdgeInsets.all(15.0),
      child: Form(
        key: _formKey,
        autovalidateMode: AutovalidateMode.onUserInteraction,
        child: Column(
          children: [
            TextFormField(
              validator: validateName,
              controller: _nameController,
              decoration: InputDecoration(
                filled: true,
                fillColor: const Color.fromARGB(0, 255, 255, 255),
                labelText: "Name",
                labelStyle:
                    const TextStyle(color: Color.fromARGB(255, 90, 98, 104)),
                contentPadding: const EdgeInsets.only(left: 10),
                border: const OutlineInputBorder(
                  borderRadius: BorderRadius.all(
                    Radius.circular(8),
                  ),
                ),
                errorBorder: OutlineInputBorder(
                  borderSide: const BorderSide(color: Colors.red),
                  borderRadius: BorderRadius.circular(12),
                ),
              ),
            ),
            const SizedBox(height: 10),
            TextFormField(
              validator: validateAge,
              controller: _ageController,
              keyboardType: TextInputType.number,
              decoration: InputDecoration(
                filled: true,
                fillColor: const Color.fromARGB(0, 255, 255, 255),
                labelText: "Age",
                labelStyle:
                    const TextStyle(color: Color.fromARGB(255, 90, 98, 104)),
                contentPadding: const EdgeInsets.only(left: 10),
                border: const OutlineInputBorder(
                  borderRadius: BorderRadius.all(
                    Radius.circular(8),
                  ),
                ),
                errorBorder: OutlineInputBorder(
                  borderSide: const BorderSide(color: Colors.red),
                  borderRadius: BorderRadius.circular(12),
                ),
              ),
            ),
            const SizedBox(height: 10),
            ElevatedButton(
                style: ButtonStyle(
                  backgroundColor:
                      MaterialStateProperty.all(Colors.deepPurple[700]),
                  minimumSize: MaterialStateProperty.all(
                    const Size.fromHeight(30),
                  ),
                ),
                onPressed: () {
                  //createRecord();
                },
                child: const Padding(
                  padding: EdgeInsets.symmetric(vertical: 15, horizontal: 25),
                  child: Text(
                    "Add",
                    style: TextStyle(fontWeight: FontWeight.bold),
                  ),
                )),
            const SizedBox(height: 10),
          ],
        ),
      ),
    );

    String? validateName(String? name) {
      if (name == null || name.isEmpty) {
        return "*required";
      } else if (name.length > 10) {
        return "Name should not be longer than 10 characters";
      }
      return null;
    }

    String? validateAge(String? age) {
      if (age == null || age.isEmpty) {
        return "*required";
      } else if (age.length > 3) {
        return "Invalid age";
      }
      return null;
    }
  }

Solution

  • Thanks to the answers by @Timur and kashif

    Here's what i did to change the borderColor of the TextFormField after validation :

    1 - Create a Stateful widget

    2 - Declare varibles for each TextFormField to hold the Validation state

    3 - Create a formKey to track the formState and set autovalidateMode: AutovalidateMode.onUserInteraction

    4 - Use validator to validate TextFormFields

    5 - Use onChanged to update the state of each TextFormField by validation variables declared earlier

    6 - Set the border color based on the value of the validation variable

    working code:

    class FormLayout extends StatefulWidget {
      const FormLayout({Key? key}) : super(key: key);
    
      @override
      State<FormLayout> createState() => _FormLayoutState();
    }
    
    class _FormLayoutState extends State<FormLayout> {
      final _nameController = TextEditingController();
    
      final _ageController = TextEditingController();
    
      final _formKey = GlobalKey<FormState>();
    
      bool _isNameValidated = false;
    
      bool _isAgeValidated = false;
    
      @override
      Widget build(BuildContext context) {
        return Padding(
          padding: const EdgeInsets.all(15.0),
          child: Form(
            key: _formKey,
            autovalidateMode: AutovalidateMode.onUserInteraction,
            child: Column(
              children: [
                TextFormField(
                  validator: validateName,
                  onChanged: (val) {
                    setState(() {
                      _isNameValidated = true;
                    });
                  },
                  controller: _nameController,
                  decoration: InputDecoration(
                    filled: true,
                    fillColor: const Color.fromARGB(0, 255, 255, 255),
                    labelText: "Name",
                    labelStyle:
                        const TextStyle(color: Color.fromARGB(255, 90, 98, 104)),
                    contentPadding: const EdgeInsets.only(left: 10),
                    border: const OutlineInputBorder(
                      borderSide: BorderSide(color: Colors.amber),
                      borderRadius: BorderRadius.all(
                        Radius.circular(8),
                      ),
                    ),
                    errorBorder: OutlineInputBorder(
                      borderSide: const BorderSide(color: Colors.red),
                      borderRadius: BorderRadius.circular(12),
                    ),
                    focusedBorder: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(10.0),
                      borderSide: BorderSide(
                          color: _isNameValidated ? Colors.green : Colors.amber),
                    ),
                    enabledBorder: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(10.0),
                      borderSide: BorderSide(
                          color: _isNameValidated ? Colors.green : Colors.grey),
                    ),
                  ),
                ),
                const SizedBox(height: 10),
                TextFormField(
                  validator: validateAge,
                  onChanged: (val) {
                    setState(() {
                      _isAgeValidated = true;
                    });
                  },
                  controller: _ageController,
                  keyboardType: TextInputType.number,
                  decoration: InputDecoration(
                    filled: true,
                    fillColor: const Color.fromARGB(0, 255, 255, 255),
                    labelText: "Age",
                    labelStyle:
                        const TextStyle(color: Color.fromARGB(255, 90, 98, 104)),
                    contentPadding: const EdgeInsets.only(left: 10),
                    border: const OutlineInputBorder(
                      borderRadius: BorderRadius.all(
                        Radius.circular(8),
                      ),
                    ),
                    errorBorder: OutlineInputBorder(
                      borderSide: const BorderSide(color: Colors.red),
                      borderRadius: BorderRadius.circular(12),
                    ),
                    focusedBorder: OutlineInputBorder(
                      borderRadius: BorderRadius.circular(10.0),
                      borderSide: BorderSide(
                          color: _isNameValidated ? Colors.green : Colors.amber),
                    ),
                    enabledBorder: OutlineInputBorder(
                      borderSide: BorderSide(
                          color: _isAgeValidated ? Colors.green : Colors.grey),
                      borderRadius: BorderRadius.circular(12),
                    ),
                  ),
                ),
                const SizedBox(height: 10),
                ElevatedButton(
                    style: ButtonStyle(
                      backgroundColor:
                          MaterialStateProperty.all(Colors.deepPurple[700]),
                      minimumSize: MaterialStateProperty.all(
                        const Size.fromHeight(30),
                      ),
                    ),
                    onPressed: () {
                      //createRecord();
                    },
                    child: const Padding(
                      padding: EdgeInsets.symmetric(vertical: 15, horizontal: 25),
                      child: Text(
                        "Add",
                        style: TextStyle(fontWeight: FontWeight.bold),
                      ),
                    )),
                const SizedBox(height: 10),
              ],
            ),
          ),
        );
      }
    
    
      //Validator Functions
    
      String? validateName(String? name) {
        if (name == null || name.isEmpty) {
          return "*required";
        } else if (name.length > 10) {
          return "Name should not be longer than 10 characters";
        }
        return null;
      }
    
      String? validateAge(String? age) {
        if (age == null || age.isEmpty) {
          return "*required";
        } else if (age.length > 3) {
          return "Invalid age";
        }
        return null;
      }