Add keyboard when using if in Textformfield in Flutter

Asked

Viewed 350 times

1

I am with a plugin to select the country code and a TextFormField to enter the email/mobile. I have a variable to display or not this CountryCode.

The problem is that when typing a number in the TextFormField the _isNumber switches to true the CountryCode appears, the TextFormField continues with the focus, but the keyboard disappears. How do I focus on email/mobile and the keyboard activated?

import 'package:country_code_picker/country_code_picker.dart';
import 'package:ebonus_app/controllers/auth_controller.dart';
import 'package:ebonus_app/utils/app_routes.dart';
import 'package:flutter/material.dart';

class LoginView extends StatefulWidget {
  @override
  _LoginViewState createState() => _LoginViewState();
}

class _LoginViewState extends State<LoginView> {
  final _formKey = GlobalKey<FormState>();
  final _identifierController = TextEditingController();
  final _passwordController = TextEditingController();
  bool _isNumber = false;
  CountryCode _countryCode;
  bool _isLoading = false;
  FocusNode _focusNodeEmailPhone;
  FocusNode _focusNodePassword;

  final _authController = AuthController();

  @override
  void initState() {
    super.initState();
    _identifierController.addListener(_onChangeTextInput);
    _focusNodeEmailPhone = FocusNode();
    _focusNodePassword = FocusNode();
  }

  @override
  void dispose() {
    _focusNodeEmailPhone.dispose();
    _focusNodePassword.dispose();
    _identifierController.dispose();
    _passwordController.dispose();
    super.dispose();
  }

  void _onChangeTextInput() {
    setState(() {
      _isNumber = isNumeric(_identifierController.text);
    });
  }

  bool isNumeric(String string) {
    return double.tryParse(string) != null;
  }

  void changeCountryCode(CountryCode code) {
    _countryCode = code;
  }

  void _submit() async {
    if (!_formKey.currentState.validate()) {
      return;
    }

    setState(() {
      _isLoading = true;
    });

    String countryCode = _countryCode.toString();
    countryCode = countryCode.substring(1);
    String identification = _isNumber ? countryCode + '-' + _identifierController.text : _identifierController.text;
    String password = _passwordController.text;

    try {
      await _authController.login(identification, password);

      Navigator.pushReplacementNamed(context, AppRoutes.HOME);
    } catch (error) {
      print(error);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: SingleChildScrollView(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Column(
                children: [
                  Image.asset(
                    'assets/images/logo.png',
                    width: 300,
                  ),
                  Padding(
                    padding: const EdgeInsets.symmetric(
                      vertical: 20,
                    ),
                    child: Text(
                      'Acesse sua conta eBonus',
                      textAlign: TextAlign.center,
                      style: TextStyle(
                        fontSize: 20,
                      ),
                    ),
                  ),
                ],
              ),
              Container(
                margin: EdgeInsets.fromLTRB(30, 20, 30, 20),
                child: Card(
                  elevation: 8.0,
                  child: Padding(
                    padding: const EdgeInsets.all(20.0),
                    child: Form(
                      key: _formKey,
                      child: Column(
                        children: <Widget>[
                          Row(
                            children: [
                              if (_isNumber)
                                Expanded(
                                  flex: 1,
                                  child: CountryCodePicker(
                                    onChanged: changeCountryCode,
                                    initialSelection: 'BR',
                                    favorite: ['+55', 'BR'],
                                    countryFilter: ['BR', 'US'],
                                    flagWidth: 25,
                                    alignLeft: true,
                                    onInit: (code) => changeCountryCode(code),
                                  ),
                                ),
                              Expanded(
                                flex: _isNumber ? 2 : 1,
                                child: TextFormField(
                                  focusNode: _focusNodeEmailPhone,
                                  textInputAction: TextInputAction.next,
                                  decoration: InputDecoration(
                                    icon: _isNumber ? null : Icon(Icons.login),
                                    labelText: 'Digite seu celular ou email *',
                                  ),
                                  keyboardType: TextInputType.text,
                                  controller: _identifierController,
                                  validator: (value) {
                                    if (value.isEmpty) {
                                      return 'Campo obrigatório';
                                    }
                                    return null;
                                  },
                                ),
                              ),
                            ],
                          ),
                          TextFormField(
                            focusNode: _focusNodePassword,
                            textInputAction: TextInputAction.done,
                            decoration: const InputDecoration(
                              icon: Icon(Icons.vpn_key),
                              labelText: 'Senha *',
                            ),
                            keyboardType: TextInputType.text,
                            controller: _passwordController,
                            obscureText: true,
                            validator: (value) {
                              if (value.isEmpty) {
                                return 'Campo obrigatório';
                              }
                              return null;
                            },
                          ),
                          SizedBox(height: 30),
                          _isLoading
                              ? CircularProgressIndicator()
                              : Container(
                                  width: double.infinity,
                                  child: RaisedButton(
                                    onPressed: _submit,
                                    color: Colors.blue,
                                    textColor: Colors.white,
                                    padding: EdgeInsets.symmetric(
                                      vertical: 12,
                                    ),
                                    child: Text('Acessar minha conta'.toUpperCase(),
                                        style: TextStyle(
                                          fontSize: 15,
                                        )),
                                  ),
                                ),
                          SizedBox(height: 10),
                          FlatButton(
                            onPressed: () {
                              Navigator.of(context).pushReplacementNamed(AppRoutes.REGISTER_CUSTOMER);
                            },
                            child: Text(
                              "Não possui uma conta? Crie aqui",
                              style: TextStyle(
                                color: Colors.blue,
                              ),
                            ),
                          ),
                          FlatButton(
                            onPressed: () {},
                            child: Text(
                              "Esqueci minha senha",
                              style: TextStyle(
                                color: Colors.blue,
                              ),
                            ),
                          ),
                        ],
                      ),
                    ),
                  ),
                ),
              )
            ],
          ),
        ),
      ),
    );
  }
} 

inserir a descrição da imagem aqui

inserir a descrição da imagem aqui

Observing: By separating Countrycode and Textformfield into two Rows the problem does not occur, but breaks down the layout it should have.

Column(
                        children: <Widget>[
                          Row(
                            children: [
                              if (_isNumber)
                                Expanded(
                                  flex: 1,
                                  child: CountryCodePicker(
                                    onChanged: changeCountryCode,
                                    initialSelection: 'BR',
                                    favorite: ['+55', 'BR'],
                                    countryFilter: ['BR', 'US'],
                                    flagWidth: 25,
                                    alignLeft: true,
                                    onInit: (code) => changeCountryCode(code),
                                  ),
                                ),
                            ],
                          ),
                          Row(
                            children: [
                              Expanded(
                                flex: _isNumber ? 2 : 1,
                                child: TextFormField(
                                  focusNode: _focusNodeEmailPhone,
                                  textInputAction: TextInputAction.next,
                                  decoration: InputDecoration(
                                    icon: _isNumber ? null : Icon(Icons.login),
                                    labelText: 'Digite seu celular ou email *',
                                  ),
                                  keyboardType: TextInputType.text,
                                  controller: _identifierController,
                                  validator: (value) {
                                    if (value.isEmpty) {
                                      return 'Campo obrigatório';
                                    }
                                    return null;
                                  },
                                ),
                              ),
                            ],
                          ),

1 answer

3


I couldn’t accurately reproduce your problem, but I was able to get to something close and it might help you...

In his Row that possessed the problem, make the following modification:

  Row(
    children: [
      (_isNumber)   // <----
        ? Expanded( // <----
          flex: 1,
          child: CountryCodePicker(
            onChanged: changeCountryCode,
            initialSelection: 'BR',
            favorite: ['+55', 'BR'],
            countryFilter: ['BR', 'US'],
            flagWidth: 25,
            alignLeft: true,
            onInit: (code) => changeCountryCode(code),
          ),
        )
       : Container(), // <----
      Expanded(
        flex: _isNumber ? 2 : 1,
        child: TextFormField(
          focusNode: _focusNodeEmailPhone,
          textInputAction: TextInputAction.next,
          decoration: InputDecoration(
            icon: _isNumber ? null : Icon(Icons.login),
            labelText: 'Digite seu celular ou email *',
          ),
          keyboardType: TextInputType.text,
          controller: _identifierController,
          validator: (value) {
            if (value.isEmpty) {
              return 'Campo obrigatório';
            }
            return null;
          },
        ),
      ),
    ],
  ),

This time I will owe a decent explanation... But I will try to clarify what I understood...

From what I saw and understood, the way you had done, your Row had only one Widget at the beginning, this due to validation _isNumber. So when typing a number and the validation works, a new Widget was added on this Row causing a conflict of Index and Focus (I believe); With my answer, you will always have 2 Widgets in your Row, making the validation only update one of them, without modifying their position within the Row.

  • Your solution worked. Can you explain to me why the way I did was wrong?

  • 1

    @Marcelo Implementei my answer.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.