skip to Main Content

I try to use FocusNode() in TextFormField so it will detect when I focus on the TextFormField, the text above will have it’s color changed. But it seems not working, what seems to be the problem?
enter image description here

import 'package:flutter/material.dart';

class SignIn extends StatefulWidget {
  const SignIn({Key? key}) : super(key: key);

  @override
  _SignInState createState() => _SignInState();
}

class _SignInState extends State<SignIn> {
  bool isPasswordVisible = false;
  bool _isEmail = true;
  bool _isPassword = true;
  TextEditingController emailInput = TextEditingController();
  TextEditingController passwordInput = TextEditingController();
  FocusNode emailText = FocusNode();

  @override
  Widget build(BuildContext context) {
   return Scaffold(
      appBar: AppBar(),
      body: SingleChildScrollView(
        child: Container(
          padding: EdgeInsets.all(30.0),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.start,
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                'Sign In to Coinify',
                style: TextStyle(
                  fontWeight: FontWeight.bold,
                  fontSize: 24.0,
                  fontFamily: "Graphik",
                )
              ),
              SizedBox(height: 20.0),
              Column(
                mainAxisAlignment: MainAxisAlignment.start,
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    'Email',
                    style: TextStyle(
                      fontWeight: FontWeight.w600,
                      fontSize: 16.0,
                      color: emailText.hasFocus ? Colors.blue : Colors.black,
                      fontFamily: "Graphik",
                    ),
                  ),
                  SizedBox(height: 8.0),
                  TextFormField(
                    focusNode: emailText,
                    controller: emailInput,
                    decoration: InputDecoration(
                      contentPadding: EdgeInsets.symmetric(vertical: 10, horizontal: 10),
                      border: OutlineInputBorder(),
                      enabledBorder: OutlineInputBorder(
                        borderSide: BorderSide(color: Colors.grey)
                      ),
                      focusedBorder: OutlineInputBorder(
                        borderSide: BorderSide(color: Colors.blue)
                      ),
                      errorBorder: OutlineInputBorder(
                        borderSide: BorderSide(color: Colors.red),
                      ),
                      focusedErrorBorder: OutlineInputBorder(
                        borderSide: BorderSide(color: Colors.red)
                      ),
                      hintText: 'Enter your email',
                      errorText: _isEmail ? null : "Email must not be empty",
                    ),
                  )
                ],
              ),
              SizedBox(height: 20.0),
              Column(
                mainAxisAlignment: MainAxisAlignment.start,
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    'Password',
                    style: TextStyle(
                      fontWeight: FontWeight.w600,
                      fontSize: 16.0,
                      fontFamily: "Graphik",
                    ),
                  ),
                  SizedBox(height: 8.0),
                  TextFormField(
                    controller: passwordInput,
                    obscureText: !isPasswordVisible,
                    decoration: InputDecoration(
                      contentPadding: EdgeInsets.symmetric(vertical: 10, horizontal: 10),
                      border: OutlineInputBorder(),
                      enabledBorder: OutlineInputBorder(
                        borderSide: BorderSide(color: Colors.grey)
                      ),
                      focusedBorder: OutlineInputBorder(
                        borderSide: BorderSide(color: Colors.blue)
                      ),
                      errorBorder: OutlineInputBorder(
                        borderSide: BorderSide(color: Colors.red),
                      ),
                      focusedErrorBorder: OutlineInputBorder(
                        borderSide: BorderSide(color: Colors.red),
                      ),
                      hintText: 'Enter your password',
                      errorText: _isPassword ? null : "Password must not be empty",
                      suffixIcon: GestureDetector(
                        onTap: () {
                          setState(() {
                            isPasswordVisible = !isPasswordVisible;
                          });
                        },
                        child: Icon(
                          isPasswordVisible ? Icons.visibility : Icons.visibility_off,
                        ),
                      ),
                    ),
                  )
                ],
              ),
              SizedBox(height: 50.0),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  MouseRegion(
                    cursor: SystemMouseCursors.click,
                    child: GestureDetector(
                      onTap: () {
                        Navigator.pushNamed(context, '/forgot-password');
                      },
                      child: Text(
                        'Forgot password?',
                        style: TextStyle(
                          color: Colors.blue,
                        )
                      )
                    )
                  ),
                  MouseRegion(
                    cursor: SystemMouseCursors.click,
                    child: GestureDetector(
                      onTap: () {
                        Navigator.pushNamed(context, '/privacy-policy');
                      },
                      child: Text(
                        'Privacy policy',
                        style: TextStyle(
                          color: Colors.blue,
                        )
                      )
                    )
                  ),
                ]
              ),
              SizedBox(height: 20.0),
              ElevatedButton(
                onPressed: () {
                  setState(() {
                    if(emailInput.text == ""){_isEmail = false;}
                    else{_isEmail = true;}
                    if(passwordInput.text == ""){_isPassword = false;}
                    else{_isPassword = true;}
                    if(_isEmail && _isPassword) {Navigator.pushNamed(context, '/sign-in-code');}
                  });
                },
                child: Text(
                  "Sign in",
                  style: TextStyle(
                    fontSize: 14.0,
                    fontWeight: FontWeight.normal,
                    color: Colors.white
                  ),
                ),
                style: ButtonStyle(
                  shape: MaterialStateProperty.all<RoundedRectangleBorder>(
                    RoundedRectangleBorder(borderRadius: BorderRadius.circular(5.0))
                  ),
                  minimumSize: MaterialStateProperty.all(Size.fromHeight(60.0)),
                  backgroundColor: MaterialStateProperty.all(Colors.blue),
                  shadowColor: MaterialStateProperty.all(Colors.transparent)
                ),
              )
            ]
          )
        ),
      )
    );  
  }
}

I have tried to change the color in the ternary operator and realized that the Color seems to stuck in false value

4

Answers


  1. The state is not changing when the focus is changed, therefore the text color doesn’t change.

    You must listen to the FocusNode changes and setState after any changes. Update your widget like this:

    FocusNode emailText = FocusNode();
    Color _emailTextColor = Colors.black;
    
    _onEmailFocusChange() {
      setState(() {
        _emailTextColor = emailText.hasFocus ? Colors.blue : Colors.black;
      });
    }
    
    @override
    void initState() {
      emailText.addListener(_onEmailFocusChange);
      super.initState();
    }
    
    @override
    void dispose() {
      super.dispose();
      emailText.removeListener(_onEmailFocusChange);
      emailText.dispose();
    }
    

    Use _emailTextColor as your text color inside TextStyle.

    Login or Signup to reply.
  2. You should add a listener to focusNode value to detect where the TextFormField is being focused or not.

    I prefer to use ValueNotifier and ValueListenableBuilder to rebuild only the Text widget not all the widgets in the screen.

    final isEmailFocused = ValueNotifier<bool>(false);
    
    @override
    void initState() {
      super.initState();
      emailText.addListener(() {
        isEmailFocused.value = emailText.hasFocus;
      });
    }
    
    @override
    void dispose() {
      // don't forget to dispose all the inputs notifiers.
      emailText.dispose();
      emailInput.dispose();
      isEmailFocused.removeListener(() {});
      isEmailFocused.dispose();
      super.dispose();
    }
    

    In Build method I wrapped the Email Text Widget with ValueListenableBuilder widget to rebuild the widget if the emailInput is focused.

    ValueListenableBuilder(
      valueListenable: isEmailFocused,
      builder: (BuildContext context, bool value, Widget? child) {
        return Text(
          'Email',
             style: TextStyle(
             fontWeight: FontWeight.w600,
             fontSize: 16.0,
             color: value ? Colors.blue : Colors.black,
             fontFamily: "Graphik",
           ),
         );
       },
     ),
    
    Login or Signup to reply.
  3. You may add the setState method as a listener to the FocusNode object named emailText. This will change the color of the Text you want to change based on the focus on the TextField.

    Modified code:

    
    class _SignInState extends State<SignIn> {
      bool isPasswordVisible = false;
      bool _isEmail = true;
      bool _isPassword = true;
      TextEditingController emailInput = TextEditingController();
      TextEditingController passwordInput = TextEditingController();
      FocusNode emailText = FocusNode();
    
      @override
      void initState() {
        super.initState();
        emailText.addListener(() => setState(() {}));
      }
    
      // Rest of your code
    }
    
    Login or Signup to reply.
  4. The problem is because your UI is not rebuild when you focus the TextField.
    You must call the setState() to update your UI.

    Method 1: Using your existing FocusNode

    Since you have already creating the focus node and set color in the ternary operator, you just need to add the following code:

    class _SignInState extends State<SignIn> {
      ...
      FocusNode emailText = FocusNode();
      ...
      
      // add listener to your FocusNode
      @override
      void initState() {
        super.initState();
        emailText.addListener(_onEmailFocusChange);
      }
      
      // the listener action is setting state when focus change
      void _onEmailFocusChange() {
        setState(() {});
        debugPrint("Email is focus: ${emailText.hasFocus.toString()}");
      }
      
      // don't forget to dispose your listener
      @override
      void dispose() {
        super.dispose();
        emailText.removeListener(_onEmailFocusChange);
        emailText.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        ...
        ...
        ...
      }
    }
    

    And this is your final code:

    import 'package:flutter/material.dart';
    
    class SignIn extends StatefulWidget {
      const SignIn({Key? key}) : super(key: key);
    
      @override
      _SignInState createState() => _SignInState();
    }
    
    class _SignInState extends State<SignIn> {
      bool isPasswordVisible = false;
      bool _isEmail = true;
      bool _isPassword = true;
      TextEditingController emailInput = TextEditingController();
      TextEditingController passwordInput = TextEditingController();
      FocusNode emailText = FocusNode();
    
      @override
      void initState() {
        super.initState();
        emailText.addListener(_onEmailFocusChange);
      }
    
      void _onEmailFocusChange() {
        setState(() {});
        debugPrint("Email is focus: ${emailText.hasFocus.toString()}");
      }
    
      @override
      void dispose() {
        super.dispose();
        emailText.removeListener(_onEmailFocusChange);
        emailText.dispose();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(),
            body: SingleChildScrollView(
              child: Container(
                  padding: EdgeInsets.all(30.0),
                  child: Column(
                      mainAxisAlignment: MainAxisAlignment.start,
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text('Sign In to Coinify',
                            style: TextStyle(
                              fontWeight: FontWeight.bold,
                              fontSize: 24.0,
                              fontFamily: "Graphik",
                            )),
                        SizedBox(height: 20.0),
                        Column(
                          mainAxisAlignment: MainAxisAlignment.start,
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Text(
                              'Email',
                              style: TextStyle(
                                fontWeight: FontWeight.w600,
                                fontSize: 16.0,
                                color:
                                    emailText.hasFocus ? Colors.blue : Colors.black,
                                fontFamily: "Graphik",
                              ),
                            ),
                            SizedBox(height: 8.0),
                            TextFormField(
                              focusNode: emailText,
                              controller: emailInput,
                              decoration: InputDecoration(
                                contentPadding: EdgeInsets.symmetric(
                                    vertical: 10, horizontal: 10),
                                border: OutlineInputBorder(),
                                enabledBorder: OutlineInputBorder(
                                    borderSide: BorderSide(color: Colors.grey)),
                                focusedBorder: OutlineInputBorder(
                                    borderSide: BorderSide(color: Colors.blue)),
                                errorBorder: OutlineInputBorder(
                                  borderSide: BorderSide(color: Colors.red),
                                ),
                                focusedErrorBorder: OutlineInputBorder(
                                    borderSide: BorderSide(color: Colors.red)),
                                hintText: 'Enter your email',
                                errorText:
                                    _isEmail ? null : "Email must not be empty",
                              ),
                            )
                          ],
                        ),
                        SizedBox(height: 20.0),
                        Column(
                          mainAxisAlignment: MainAxisAlignment.start,
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Text(
                              'Password',
                              style: TextStyle(
                                fontWeight: FontWeight.w600,
                                fontSize: 16.0,
                                fontFamily: "Graphik",
                              ),
                            ),
                            SizedBox(height: 8.0),
                            TextFormField(
                              controller: passwordInput,
                              obscureText: !isPasswordVisible,
                              decoration: InputDecoration(
                                contentPadding: EdgeInsets.symmetric(
                                    vertical: 10, horizontal: 10),
                                border: OutlineInputBorder(),
                                enabledBorder: OutlineInputBorder(
                                    borderSide: BorderSide(color: Colors.grey)),
                                focusedBorder: OutlineInputBorder(
                                    borderSide: BorderSide(color: Colors.blue)),
                                errorBorder: OutlineInputBorder(
                                  borderSide: BorderSide(color: Colors.red),
                                ),
                                focusedErrorBorder: OutlineInputBorder(
                                  borderSide: BorderSide(color: Colors.red),
                                ),
                                hintText: 'Enter your password',
                                errorText: _isPassword
                                    ? null
                                    : "Password must not be empty",
                                suffixIcon: GestureDetector(
                                  onTap: () {
                                    setState(() {
                                      isPasswordVisible = !isPasswordVisible;
                                    });
                                  },
                                  child: Icon(
                                    isPasswordVisible
                                        ? Icons.visibility
                                        : Icons.visibility_off,
                                  ),
                                ),
                              ),
                            )
                          ],
                        ),
                        SizedBox(height: 50.0),
                        Row(
                            mainAxisAlignment: MainAxisAlignment.spaceBetween,
                            children: [
                              MouseRegion(
                                  cursor: SystemMouseCursors.click,
                                  child: GestureDetector(
                                      onTap: () {
                                        Navigator.pushNamed(
                                            context, '/forgot-password');
                                      },
                                      child: Text('Forgot password?',
                                          style: TextStyle(
                                            color: Colors.blue,
                                          )))),
                              MouseRegion(
                                  cursor: SystemMouseCursors.click,
                                  child: GestureDetector(
                                      onTap: () {
                                        Navigator.pushNamed(
                                            context, '/privacy-policy');
                                      },
                                      child: Text('Privacy policy',
                                          style: TextStyle(
                                            color: Colors.blue,
                                          )))),
                            ]),
                        SizedBox(height: 20.0),
                        ElevatedButton(
                          onPressed: () {
                            setState(() {
                              if (emailInput.text == "") {
                                _isEmail = false;
                              } else {
                                _isEmail = true;
                              }
                              if (passwordInput.text == "") {
                                _isPassword = false;
                              } else {
                                _isPassword = true;
                              }
                              if (_isEmail && _isPassword) {
                                Navigator.pushNamed(context, '/sign-in-code');
                              }
                            });
                          },
                          child: Text(
                            "Sign in",
                            style: TextStyle(
                                fontSize: 14.0,
                                fontWeight: FontWeight.normal,
                                color: Colors.white),
                          ),
                          style: ButtonStyle(
                              shape:
                                  MaterialStateProperty.all<RoundedRectangleBorder>(
                                      RoundedRectangleBorder(
                                          borderRadius:
                                              BorderRadius.circular(5.0))),
                              minimumSize:
                                  MaterialStateProperty.all(Size.fromHeight(60.0)),
                              backgroundColor:
                                  MaterialStateProperty.all(Colors.blue),
                              shadowColor:
                                  MaterialStateProperty.all(Colors.transparent)),
                        )
                      ])),
            ));
      }
    }
    

    Method 2: Using Focus widget

    The second method is more simple, it just only wrap your TextFormField with Focus widget and call the setState in the onFocusChange like below:

    Focus(   // <- wrap with this
      onFocusChange: (focus) {
        setState(() {});   // <- and call setState
        print("Email is focus: $focus");
      },
      child: TextFormField(
        focusNode: emailText,
        controller: emailInput,
        decoration: InputDecoration(
          ...
        ),
      ),
    ),
    

    And this is your final code using this method:

    import 'package:flutter/material.dart';
    
    class SignIn extends StatefulWidget {
      const SignIn({Key? key}) : super(key: key);
    
      @override
      _SignInState createState() => _SignInState();
    }
    
    class _SignInState extends State<SignIn> {
      bool isPasswordVisible = false;
      bool _isEmail = true;
      bool _isPassword = true;
      TextEditingController emailInput = TextEditingController();
      TextEditingController passwordInput = TextEditingController();
      FocusNode emailText = FocusNode();
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
            appBar: AppBar(),
            body: SingleChildScrollView(
              child: Container(
                  padding: EdgeInsets.all(30.0),
                  child: Column(
                      mainAxisAlignment: MainAxisAlignment.start,
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text('Sign In to Coinify',
                            style: TextStyle(
                              fontWeight: FontWeight.bold,
                              fontSize: 24.0,
                              fontFamily: "Graphik",
                            )),
                        SizedBox(height: 20.0),
                        Column(
                          mainAxisAlignment: MainAxisAlignment.start,
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Text(
                              'Email',
                              style: TextStyle(
                                fontWeight: FontWeight.w600,
                                fontSize: 16.0,
                                color:
                                    emailText.hasFocus ? Colors.blue : Colors.black,
                                fontFamily: "Graphik",
                              ),
                            ),
                            SizedBox(height: 8.0),
                            Focus(
                              onFocusChange: (focus) {
                                setState(() {});
                                print("Email is focus: $focus");
                              },
                              child: TextFormField(
                                focusNode: emailText,
                                controller: emailInput,
                                decoration: InputDecoration(
                                  contentPadding: EdgeInsets.symmetric(
                                      vertical: 10, horizontal: 10),
                                  border: OutlineInputBorder(),
                                  enabledBorder: OutlineInputBorder(
                                      borderSide: BorderSide(color: Colors.grey)),
                                  focusedBorder: OutlineInputBorder(
                                      borderSide: BorderSide(color: Colors.blue)),
                                  errorBorder: OutlineInputBorder(
                                    borderSide: BorderSide(color: Colors.red),
                                  ),
                                  focusedErrorBorder: OutlineInputBorder(
                                      borderSide: BorderSide(color: Colors.red)),
                                  hintText: 'Enter your email',
                                  errorText:
                                      _isEmail ? null : "Email must not be empty",
                                ),
                              ),
                            ),
                          ],
                        ),
                        SizedBox(height: 20.0),
                        Column(
                          mainAxisAlignment: MainAxisAlignment.start,
                          crossAxisAlignment: CrossAxisAlignment.start,
                          children: [
                            Text(
                              'Password',
                              style: TextStyle(
                                fontWeight: FontWeight.w600,
                                fontSize: 16.0,
                                fontFamily: "Graphik",
                              ),
                            ),
                            SizedBox(height: 8.0),
                            TextFormField(
                              controller: passwordInput,
                              obscureText: !isPasswordVisible,
                              decoration: InputDecoration(
                                contentPadding: EdgeInsets.symmetric(
                                    vertical: 10, horizontal: 10),
                                border: OutlineInputBorder(),
                                enabledBorder: OutlineInputBorder(
                                    borderSide: BorderSide(color: Colors.grey)),
                                focusedBorder: OutlineInputBorder(
                                    borderSide: BorderSide(color: Colors.blue)),
                                errorBorder: OutlineInputBorder(
                                  borderSide: BorderSide(color: Colors.red),
                                ),
                                focusedErrorBorder: OutlineInputBorder(
                                  borderSide: BorderSide(color: Colors.red),
                                ),
                                hintText: 'Enter your password',
                                errorText: _isPassword
                                    ? null
                                    : "Password must not be empty",
                                suffixIcon: GestureDetector(
                                  onTap: () {
                                    setState(() {
                                      isPasswordVisible = !isPasswordVisible;
                                    });
                                  },
                                  child: Icon(
                                    isPasswordVisible
                                        ? Icons.visibility
                                        : Icons.visibility_off,
                                  ),
                                ),
                              ),
                            )
                          ],
                        ),
                        SizedBox(height: 50.0),
                        Row(
                            mainAxisAlignment: MainAxisAlignment.spaceBetween,
                            children: [
                              MouseRegion(
                                  cursor: SystemMouseCursors.click,
                                  child: GestureDetector(
                                      onTap: () {
                                        Navigator.pushNamed(
                                            context, '/forgot-password');
                                      },
                                      child: Text('Forgot password?',
                                          style: TextStyle(
                                            color: Colors.blue,
                                          )))),
                              MouseRegion(
                                  cursor: SystemMouseCursors.click,
                                  child: GestureDetector(
                                      onTap: () {
                                        Navigator.pushNamed(
                                            context, '/privacy-policy');
                                      },
                                      child: Text('Privacy policy',
                                          style: TextStyle(
                                            color: Colors.blue,
                                          )))),
                            ]),
                        SizedBox(height: 20.0),
                        ElevatedButton(
                          onPressed: () {
                            setState(() {
                              if (emailInput.text == "") {
                                _isEmail = false;
                              } else {
                                _isEmail = true;
                              }
                              if (passwordInput.text == "") {
                                _isPassword = false;
                              } else {
                                _isPassword = true;
                              }
                              if (_isEmail && _isPassword) {
                                Navigator.pushNamed(context, '/sign-in-code');
                              }
                            });
                          },
                          child: Text(
                            "Sign in",
                            style: TextStyle(
                                fontSize: 14.0,
                                fontWeight: FontWeight.normal,
                                color: Colors.white),
                          ),
                          style: ButtonStyle(
                              shape:
                                  MaterialStateProperty.all<RoundedRectangleBorder>(
                                      RoundedRectangleBorder(
                                          borderRadius:
                                              BorderRadius.circular(5.0))),
                              minimumSize:
                                  MaterialStateProperty.all(Size.fromHeight(60.0)),
                              backgroundColor:
                                  MaterialStateProperty.all(Colors.blue),
                              shadowColor:
                                  MaterialStateProperty.all(Colors.transparent)),
                        )
                      ])),
            ));
      }
    }
    

    And this is the result:

    demo

    Hopefully it can solve your problem, Thanks 😉

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search