简体   繁体   中英

How to pass function onChanged with dynamic variable from reusable widget to other screen in flutter?

I need to pass the function onChanged of StringInputTextBox into the textbox on the login page. However, it shows the error "The argument type 'void Function(dynamic)' can't be assigned to the parameter type 'void Function()?'." in the login.dart. The main aim is to print the input of the email and password textbox in the debug console. I don't know how to declare the function of StringInputTextBox with a dynamic variable. Your help is much appreciated.

login.dart

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

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

class _LoginState extends State<Login> {

  //text field state
  String email = '';
  String password = '';

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
      onTap: () {
        FocusScopeNode currentFocus = FocusScope.of(context);

        if (!currentFocus.hasPrimaryFocus) {
          currentFocus.unfocus();
        }
      },
      child: Scaffold(
          body: SafeArea(
              child: Center(
        child: SingleChildScrollView(
          child: Column(children: [
            Padding(
              padding: const EdgeInsets.fromLTRB(0, 20, 0, 20),
              child: Image.asset(
                'assets/images/app_logo_large.png',
                height: 200,
                width: 200,
              ),
            ),
            Container(
              padding: const EdgeInsets.fromLTRB(0, 0, 0, 20),
              child: Column(
                children: const [
                  Text('Welcome To', style: landingLabelStyle),
                  SizedBox(
                    height: 10,
                  ),
                  Text('JustShop', style: landingLabelStyle),
                ],
              ),
            ),
            StringInputTextBox(
                inputLabelText: 'Username',
                onChanged: (val) {
                  setState(() => email = val);
                }),
            StringInputTextBox(
              inputLabelText: 'Password',
              onChanged: (val) {
                setState(() => password = val);
              },
            ),
            Padding(
                padding: const EdgeInsets.fromLTRB(30, 0, 30, 0),
                child: Row(mainAxisAlignment: MainAxisAlignment.end, children: [
                  LinkButton(
                    buttonText: 'Forgot your password?',
                    onClick: () {
                      Navigator.pushNamed(context, '/forgetpassword');
                    },
                  ),
                ])),
            const SizedBox(height: 20),
            BlackTextButton(
              buttonText: 'LOG IN',
              onClick: () async {
                print(email);
                print(password);
              },
            ),
            Padding(
              padding: const EdgeInsets.fromLTRB(30, 0, 30, 0),
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: [
                  const Text('Need a JustShop Account?'),
                  LinkButton(
                    buttonText: 'Sign up here',
                    onClick: () {
                      Navigator.pushNamed(context, '/signup');
                    },
                  )
                ],
              ),
            )
          ]),
        ),
      ))),
    );
  }
}

input_text_box.dart

class StringInputTextBox extends StatefulWidget {
  final String inputLabelText;
  final VoidCallback? onChanged;

  const StringInputTextBox(
      {Key? key, required this.inputLabelText, required this.onChanged})
      : super(key: key);

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

class _StringInputTextBoxState extends State<StringInputTextBox> {
  final formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Form(
      key: formKey,
      child: Padding(
        padding: const EdgeInsets.fromLTRB(35, 10, 35, 0),
        child: TextFormField(
          cursorHeight: 18,
          cursorColor: Colors.black,
          decoration: InputDecoration(
            labelText: widget.inputLabelText,
            floatingLabelStyle: const TextStyle(
              fontSize: 20,
              color: secondaryColor,
            ),
            contentPadding: const EdgeInsets.fromLTRB(20, 0, 20, 0),
            floatingLabelBehavior: FloatingLabelBehavior.auto,
            enabledBorder: const OutlineInputBorder(
              borderRadius: BorderRadius.zero,
            ),
            focusedBorder: const OutlineInputBorder(
              borderRadius: BorderRadius.zero,
            ),
          ),
          style: primaryFontStyle,
        ),
      ),
      onChanged: () => widget.onChanged,
    );
  }
}

You should do something like this

  1. create a TextEditingController instance to control the value in the input
  2. Link the controller to the TextFormField
  3. Pass the value of the controller to the callback using _inputController.text

input_text_box.dart

class StringInputTextBox extends StatefulWidget {
  final String inputLabelText;
  final VoidCallback? onChanged;

  const StringInputTextBox(
      {Key? key, required this.inputLabelText, required this.onChanged})
      : super(key: key);

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

class _StringInputTextBoxState extends State<StringInputTextBox> {
  final formKey = GlobalKey<FormState>();
  
  // 1. Create a TextEditingController instance
  final TextEditingController _inputController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Form(
      key: formKey,
      child: Padding(
        padding: const EdgeInsets.fromLTRB(35, 10, 35, 0),
        child: TextFormField(
          // 2. link TextEditingController instance with the input
          controller: _inputController,
          cursorHeight: 18,
          cursorColor: Colors.black,
          decoration: InputDecoration(
            labelText: widget.inputLabelText,
            floatingLabelStyle: const TextStyle(
              fontSize: 20,
              color: secondaryColor,
            ),
            contentPadding: const EdgeInsets.fromLTRB(20, 0, 20, 0),
            floatingLabelBehavior: FloatingLabelBehavior.auto,
            enabledBorder: const OutlineInputBorder(
              borderRadius: BorderRadius.zero,
            ),
            focusedBorder: const OutlineInputBorder(
              borderRadius: BorderRadius.zero,
            ),
          ),
          style: primaryFontStyle,
        ),
      ),
      // 3. Pass your value to the callback
      onChanged: () => widget.onChanged(_inputController.text),
    );
  }
}

And now you can get val in your login.dart

StringInputTextBox(
  inputLabelText: 'Username',
  // 4. This is the value of the controller
  onChanged: (String val) {
    setState(() => email = val);
  }),

Let me know if you need more help.

Change your code as follows

class StringInputTextBox extends StatefulWidget {
      final String inputLabelText;
      final ValueChanged<String>? onChanged;
    
      const StringInputTextBox(
          {Key? key, required this.inputLabelText, required this.onChanged})
          : super(key: key);
    
      @override
      _StringInputTextBoxState createState() => _StringInputTextBoxState();
    }
    
    class _StringInputTextBoxState extends State<StringInputTextBox> {
      final formKey = GlobalKey<FormState>();
    
      @override
      Widget build(BuildContext context) {
        return Form(
          key: formKey,
          child: Padding(
            padding: const EdgeInsets.fromLTRB(35, 10, 35, 0),
            child: TextFormField(
              cursorHeight: 18,
              cursorColor: Colors.black,
              decoration: InputDecoration(
                labelText: widget.inputLabelText,
                floatingLabelStyle: const TextStyle(
                  fontSize: 20,
                  color: secondaryColor,
                ),
                contentPadding: const EdgeInsets.fromLTRB(20, 0, 20, 0),
                floatingLabelBehavior: FloatingLabelBehavior.auto,
                enabledBorder: const OutlineInputBorder(
                  borderRadius: BorderRadius.zero,
                ),
                focusedBorder: const OutlineInputBorder(
                  borderRadius: BorderRadius.zero,
                ),
              ),
              style: primaryFontStyle,
            ),
          ),
          onChanged: widget.onChanged,
        );
      }
    }

And now you can get val in your login.dart

StringInputTextBox(
  inputLabelText: 'Username',
  // 4. This is the value of the controller
  onChanged: (String val) {
    setState(() => email = val);
  }),

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