3

I am trying to create an overlay widget for TextFormField suffix Icon. Normally we would be using ToolTip, but just trying something new because the overlay widget can be customized. I want to change the suffix Icon Color of TextFormField if it is not validated from Grey to Red. So when the Icon becomes red it alerts the user that something is wrong, when the user clicks on it overlay widget will be shown.
My Code for OverLay widget.

void _showOverlay(BuildContext context) async {
    OverlayState? overlayState = Overlay.of(context);
    OverlayEntry overlayEntry;
    overlayEntry = OverlayEntry(builder: (context) {
      return Positioned(
        left: MediaQuery.of(context).size.width * 0.1,
        top: MediaQuery.of(context).size.height * 0.23,
        child: ClipRRect(
          borderRadius: BorderRadius.circular(10),
          child: Material(
            child: Container(
              alignment: Alignment.center,
              color: Colors.grey.shade200,
              padding:
                  EdgeInsets.all(MediaQuery.of(context).size.height * 0.02),
              width: MediaQuery.of(context).size.width * 0.8,
              height: MediaQuery.of(context).size.height * 0.06,
              child: const Text(
                'Name should be more than 2 characters',
                style: TextStyle(color: Colors.black),
              ),
            ),
          ),
        ),
      );
    });
    overlayState!.insert(overlayEntry);

    await Future.delayed(const Duration(seconds: 3));

    overlayEntry.remove();
  }

My Submit Button method:

void _submitForm() {
    setState(() {
      _autoValidateMode = AutovalidateMode.always;
    });
    final form = _formKey.currentState;
    if (form == null || !form.validate()) return;

    form.save();
    print(_name);
  }  

My TextFormField widget:

TextFormField(
                  controller: nameController,
                  keyboardType: TextInputType.name,
                  textInputAction: TextInputAction.next,
                  textCapitalization: TextCapitalization.words,
                  validator: (String? value) {
                    if (value == null || value.trim().isEmpty) {
                      return;
                    }
                    return null;
                  },
                  onSaved: (String? value) {
                    _name = value;
                  },
                  decoration: kTextInputDecoration.copyWith(
                      labelText: 'Full Name',
                      prefixIcon: const Icon(Icons.person),
                      suffixIcon: IconButton(
                          padding: EdgeInsets.zero,
                          onPressed: () {
                            _showOverlay(context);
                          },
                          icon: const Icon(
                            Icons.info,
                            color: Colors.grey //change icon color according to form validation 
                          ))),  

My submit button.

ElevatedButton(
                    onPressed: () {
                      _submitForm();
                    },
                    style: ElevatedButton.styleFrom(
                        padding: const EdgeInsets.all(10)),
                    child: const Text(
                      'Submit',
                      style: TextStyle(fontSize: 20),
                    )),  

I want to change the color of the suffix icon color when the submit button is pressed. If the form is not validated the color should change to red or the default is grey. Thank you very much in advance for your help.

sulli110
  • 145
  • 2
  • 16

2 Answers2

0

Warning: the below solution is currently broken on the stable channel 3.3.9 but it works fine in beta.
The issue was marked as fixed on August 23, 2022 so I have good hope that we will get it in stable soon.

You can:

  1. create a class which extends MaterialStateColor
  2. create an instance in your build method based on your theme
  3. pass the instance to suffixIconColor
class InfoIconColor extends MaterialStateColor {
  const InfoIconColor(
    super.defaultColor, {
    required this.disabledColor,
    required this.errorColor,
  });

  final Color disabledColor;
  final Color errorColor;

  @override
  Color resolve(Set<MaterialState> states) {
    if (states.contains(MaterialState.error)) return errorColor;
    if (states.contains(MaterialState.disabled)) return disabledColor;
    return Color(super.value);
  }
}

TextFormField(
  // ...
  decoration: kTextInputDecoration.copyWith(
    labelText: 'Full Name',
    suffixIcon: // ...
    suffixIconColor: // ...
  ),
)  

In the meantime, you can can use the same InfoIconColor in the theme of your app (or wrap your widget with a theme widget) like so:

final theme = Theme.of(context); 
Theme(
  data: theme.copyWith(
    inputDecorationTheme: theme.inputDecorationTheme.copyWith(
      suffixIconColor: //...
    ),
  ),
  child: //...
)
Gpack
  • 1,878
  • 3
  • 18
  • 45
-1

You can create bool to store the validation or directly use the validate method.

 ///state level
  bool _isValidate = true;
  ......
 /// inside TextFormField
validator: (String? value) {
  if (value == null || value.trim().isEmpty) {
    setState(() {
      _isValidate = false;
    });
    return "Error message";
  }
  return null;
},

onTap: () {
  setState(() {
    _isValidate = true;
  });
},


/// and Icon color 
icon: Icon(
  Icons.info,
  color: _isValidate ? Colors.grey : Colors.red,
),
Md. Yeasin Sheikh
  • 54,221
  • 7
  • 29
  • 56