Name
Name

Reputation: 13

Text Color didn't change

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

Upvotes: 0

Views: 105

Answers (5)

Shivam Saxena
Shivam Saxena

Reputation: 31

This is happening because you are not updating the state and resulting in ui change. Use Focus widget and setState in onFocusChange callback.

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key});

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  bool _isNodeFocus = false;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: const Text("My app"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'Email',
              style: TextStyle(
                fontWeight: FontWeight.w600,
                fontSize: 16.0,
                color: _isNodeFocus ? Colors.blue : Colors.yellow,
                fontFamily: "Graphik",
              ),
            ),
            Focus(
              onFocusChange: (hasFocus) {
                setState(() {
                  _isNodeFocus = hasFocus;
                });
              },
              child: TextFormField(),
            )
          ],
        ),
      ),
    );
  }
}

Upvotes: 0

Adan
Adan

Reputation: 626

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 😉

Upvotes: 0

Aurangzeb Hossain
Aurangzeb Hossain

Reputation: 116

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
}

Upvotes: 0

Ahmed Wafik
Ahmed Wafik

Reputation: 216

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",
       ),
     );
   },
 ),

Upvotes: 0

Warjeh
Warjeh

Reputation: 1220

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.

Upvotes: 0

Related Questions