简体   繁体   中英

Flutter TextFormField Autofocus Not working

I am working on the sign up page for me app, I have set it up to have focusnodes for each TextFormField so the user can click on the next button on keyboard to focus next field. The problem is when the page load it focuses on the bottom field even though I have the top "name" field set to autofocus.

I even try to request focus both in the onInit and I've tired right at the top of the build section.

class _SignUpScreenState extends State<SignUpScreen> {
  final _signUpFormKey = GlobalKey<FormState>();
  final TextEditingController _nameController = TextEditingController();
  final TextEditingController _emailController = TextEditingController();
  final TextEditingController _passwordController = TextEditingController();
  final _authController = Get.find<AuthController>();

  late FocusNode _nameFocus, _emailFocus, _passwordFocus, _passwordConfirmFocus;

  bool _isLoading = false;

  @override
  void initState() {
    super.initState();
    _nameFocus = FocusNode(debugLabel: 'Name Focus');
    _emailFocus = FocusNode(debugLabel: 'Email Focus');
    _passwordFocus = FocusNode(debugLabel: 'PW Focus');
    _passwordConfirmFocus = FocusNode(debugLabel: 'CPW Focus');
    _nameFocus.requestFocus();
  }

  @override
  void dispose() {
    _nameController.dispose();
    _emailController.dispose();
    _passwordController.dispose();
    _nameFocus.dispose();
    _emailFocus.dispose();
    _passwordFocus.dispose();
    _passwordConfirmFocus.dispose();
    super.dispose();
  }


 // Sign-up form Section
  Widget buildSignUpForm() {
    return Form(
      key: _signUpFormKey,
      child: Column(
        mainAxisSize: MainAxisSize.min,
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: <Widget>[
          RoundedTextFormField(
            autoFocus: true,
            focusNode: _nameFocus,
            onFieldSubmitted: _fieldFocusChange(context, _nameFocus, _emailFocus),
            keyboardType: TextInputType.name,
            keyboardAction: TextInputAction.next,
            controller: _nameController,
            hintText: 'Name',
            validator: (value) {
              if (value.toString().length <= 2 || value!.isEmpty) {
                return 'Enter a valid Name';
              }
              return null;
            },
          ),
          SizedBox(height: 10.h),
          RoundedTextFormField(
            focusNode: _emailFocus,
            onFieldSubmitted: _fieldFocusChange(context, _emailFocus, _passwordFocus),
            keyboardType: TextInputType.emailAddress,
            keyboardAction: TextInputAction.next,
            controller: _emailController,
            hintText: 'Email',
            validator: (email) => email != null && !EmailValidator.validate(email) ? 'Enter a valid email' : null,
          ),
          SizedBox(height: 10.h),
          RoundedTextFormField(
            focusNode: _passwordFocus,
            onFieldSubmitted: _fieldFocusChange(context, _passwordFocus, _passwordConfirmFocus),
            keyboardType: TextInputType.visiblePassword,
            keyboardAction: TextInputAction.next,
            obsecureText: true,
            controller: _passwordController,
            hintText: 'Password',
            validator: (value) {
              if (value.toString().length < 6 || value!.isEmpty) {
                return 'Password should be longer or equal to 6 characters.';
              }
              return null;
            },
          ),
          SizedBox(height: 10.h),
          RoundedTextFormField(
            focusNode: _passwordConfirmFocus,
            keyboardAction: TextInputAction.done,
            onFieldSubmitted: (_) {
              Utilities.logInfo('Signup Submit button Pressed');
              if (_signUpFormKey.currentState!.validate()) {
                _signUpFormKey.currentState!.save();
                setState(() {
                  _isLoading = true;
                });
                FocusScope.of(context).unfocus();
                String name = _nameController.text.trim();
                String email = _emailController.text.trim();
                String password = _passwordController.text.trim();

                Utilities.logInfo('Attempting Signup with Firebase');
                _authController.signUpWithEmail(name, email, password);
                setState(() {
                  _isLoading = false;
                });
              }
            },
            keyboardType: TextInputType.visiblePassword,
            obsecureText: true,
            hintText: 'Confirm Password',
            validator: (value) {
              if (value!.trim() != _passwordController.text.trim() || value.isEmpty) {
                return 'Passwords do not match!';
              }
              return null;
            },
          ),
          SizedBox(height: 10.h),
          _isLoading
              ? const CircularProgressIndicator() // TODO custom progress indicator
              : ElevatedButton(
                  buttonText: 'Sign Up',
                  onPressed: () {
                    Utilities.logInfo('Signup Submit button Pressed');
                    if (_signUpFormKey.currentState!.validate()) {
                      _signUpFormKey.currentState!.save();
                      setState(() {
                        _isLoading = true;
                      });
                      FocusScope.of(context).unfocus();
                      String name = _nameController.text.trim();
                      String email = _emailController.text.trim();
                      String password = _passwordController.text.trim();

                      Utilities.logInfo('Attempting Signup with Firebase');
                      _authController.signUpWithEmail(name, email, password);
                      setState(() {
                        _isLoading = false;
                      });
                    }
                  },
                ),
          SizedBox(height: 10.h),
        ],
      ),
    );
  }

and I have this method to change focus nodes

_fieldFocusChange(BuildContext context, FocusNode currentFocus, FocusNode nextFocus) {
  currentFocus.unfocus();
  FocusScope.of(context).requestFocus(nextFocus);
}

So when page loads it automatically focuses the confirm password field. I have also commented out the confirmPassword field so its just the 3 fields and then nothing gets focused when page loads. I'm a little confused why the autofocus doesnt work on the nameFocus field though.

Any help would be most appreciated.

So by adding auto focus the name field got focus at first then it called the listener because there's a change in focus

_fieldFocusChange(BuildContext context, FocusNode currentFocus, FocusNode nextFocus) {
  currentFocus.unfocus();
  FocusScope.of(context).requestFocus(nextFocus);
}

Here it loses focus and moves focus to the next widget. That's why name field doesn't get focus.

You can try

onFieldSubmitted: (){
_fieldFocusChange(context, _nameFocus, _emailFocus);
}

So the method isn't invoked automatically

After some trial and error I realized that I dont even need any of those onFieldSubmitted. Im guessing because of being inside the Form widget and using the keyboardAction: TextInputAction.next as the keyboard type. So removing all but the last onfieldSubmitted from the form seems to work like I expected it to.

thanks @KaushikChandru for pointing me in the right direction

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM