I am new to Flutter and want to build a login mask. I have two child components, one contains the input fields and the other one a login button. I am trying to call a login function when the button is pressed and access the values from the input fields there.

I am not sure whats the correct solution for my problem, I tried using a provider with a model class but, when I run the app and click in the input fields my input field and the login button disappears. I am also open for completely different solutions if they would be better in my case.

import 'package:flutter/material.dart';

class LoginModel extends ChangeNotifier {
  final loginFieldController = TextEditingController();
  void login() {
    print(loginFieldController.value);
  }
}

class LoginState extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Container(
            padding: EdgeInsets.only(top: 15, right: 15, left: 15, bottom: 380),
            child: Stack(children: <Widget>[
              LoginContentWidget(),
              LoginHeaderWidget(),
              FloatingLoginButton(),
            ])));
  }
}

class LoginHeaderWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.only(top: 15, left: 10, right: 10),
      alignment: Alignment.topCenter,
      child: Card(
          color: Colors.lightBlue,
          shape: RoundedRectangleBorder(
            borderRadius: BorderRadius.circular(10.0),
          ),
          elevation: 15,
          child: IntrinsicHeight(
            child: Row(
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                Center(
                  child: Container(
                    alignment: Alignment.topCenter,
                    margin: EdgeInsets.only(
                        top: 10, bottom: 10, left: 40, right: 40),
                    child: Text(
                      'LOGIN',
                      style: TextStyle(
                          color: Colors.amberAccent,
                          fontWeight: FontWeight.w500,
                          fontSize: 45),
                    ),
                  ),
                )
              ],
            ),
          )),
    );
  }
}

class LoginContentWidget extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => LoginContentWidgetState();
}

class LoginContentWidgetState extends State<LoginContentWidget> {
  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.only(top: 50),
      child: Card(
          elevation: 5,
          child: Padding(
            padding: EdgeInsets.only(left: 20, right: 20, top: 80, bottom: 70),
            child: Column(
              mainAxisAlignment: MainAxisAlignment.start,
              mainAxisSize: MainAxisSize.min,
              children: <Widget>[
                TextFormField(
                  controller: LoginModel().loginFieldController,
                  decoration: InputDecoration(
                      contentPadding:
                          EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),
                      hintText: 'Email'),
                ),
                TextFormField(
                  obscureText: true,
                  decoration: InputDecoration(
                      focusColor: Colors.white,
                      fillColor: Colors.white,
                      contentPadding:
                          EdgeInsets.fromLTRB(20.0, 15.0, 20.0, 15.0),
                      hintText: 'Password'),
                ),
              ],
            ),
          )),
    );
  }
}

class FloatingLoginButton extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => FloatingLoginButtonState();
}

class FloatingLoginButtonState extends State<FloatingLoginButton> {
  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.end,
      children: <Widget>[
        ButtonBar(
          alignment: MainAxisAlignment.end,
          children: <Widget>[
            FloatingActionButton.extended(
              label: Text('Login'),
              onPressed: LoginModel().login,
            )
          ],
        )
      ],
    );
  }
}


Solution 1: chunhunghan

change to this, add SingleChildScrollView and move FloatingLoginButton

class LoginState extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: SingleChildScrollView(
          child: Container(
              padding: EdgeInsets.only(top: 15, right: 15, left: 15, bottom: 380),
              child: Stack(children: <Widget>[
                LoginContentWidget(),
                LoginHeaderWidget(),
               // FloatingLoginButton(),
              ])),
        )
            ,
      floatingActionButton: FloatingLoginButton(),
    )
    ;
  }
}

Edit Question 2
declare this outside of all class

var loginModel = LoginModel();

and change

 LoginModel().loginFieldController 

to

 controller: loginModel.loginFieldController,

and also change

 LoginModel().login

to

 onPressed: loginModel.login,

enter image description here


Solution 2: Thomas Hüttmaier

In my login function I print the text from the username textfield. I don't get an error but the value is empty.

  final loginFieldController = TextEditingController();
  void login() {
    print(loginFieldController.text);
  }

[![Output][1]][1]

  [1]: https://i.stack.imgur.com/36iLt.png