【问题标题】:How to pass user's TextFormField input to a button in a different class in flutter如何将用户的TextFormField输入传递给flutter中不同类的按钮
【发布时间】:2021-05-06 13:03:06
【问题描述】:

我正在创建一个颤振应用程序。为了代码的可重用性,我需要区分电子邮件和密码表单以及登录按钮,我不确定如何正确地将输入从 textformfield 传递到按钮,以便在单击时验证表单。这是我的代码。请注意,我是 Flutter 的初学者。

//这是我的 EmailTextForm 类:

    class EmailTextForm extends StatelessWidget {
    String email;

   EmailTextForm({Key key, this.email}) : super(key: key);

  Widget build(BuildContext context) {

return Container(
    width: 370.0,
    height: 54.0,
    child: TextFormField(
      decoration: InputDecoration(
        enabledBorder: OutlineInputBorder(
            //DEFAULT STATE OF THE BORDER(FOCUSED BORDER DOWN BELOW TO HAVE MORE CONTROL OF THE FORM)
            borderSide: BorderSide(
                width: 1.0, color: Color.fromRGBO(16, 25, 53, 0.1)),
            borderRadius: BorderRadius.circular(12.0)),
        focusedBorder: OutlineInputBorder(
          //ON FOCUSED BORDER TO NOT CHANGE STATE WHILE BEING PRESSED ON
          borderSide: BorderSide(
              width: 1.0, color: Color.fromRGBO(16, 25, 53, 0.1)),
          borderRadius: BorderRadius.circular(12.0),
        ),
        prefixIcon: Icon(Icons.mail, color: Color(0xFF9FA3AE)),
        hintText: 'El.Paštas',
        hintStyle: TextStyle(
          fontFamily: 'Sora',
          fontSize: 16.0,
          color: Color(0xFF9FA3AE),
        ),
      ),
      validator: (input) =>
          !input.contains('@') ? 'Please enter a valid email' : null,
      onSaved: (input) => email = input,
    ));
 }
}

//这是按钮类。

import 'package:flutter/material.dart';
import 'dart:math' as math;

class LoginButton extends StatelessWidget {
  final _formKey = GlobalKey<FormState>();
  String email;
  String password;

  _submit() {
    if (_formKey.currentState.validate()) {
      _formKey.currentState.save();
      print('validated');
      //logging in the user
    }
  }

  @override
  Widget build(BuildContext context) {
    //Container to manipulate button design
    return Container(
        width: 370.0,
        height: 54.0,
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular((12.0)),
          gradient: LinearGradient(
            //change gradient, wrong value, maybe something in AdobeXD.
            colors: <Color>[Color(0xFF00BAFF), Color(0xFF448CFA)],
            stops: [0.0, 1.0],
            begin: Alignment(-1.0, 0.0),
            end: Alignment(1.0, 0.0),
            transform: GradientRotation(math.pi / 2),
          ),
          boxShadow: [
            BoxShadow(
              color: Color.fromRGBO(48, 183, 241, 1.0),
              offset: Offset(0.0, 4.0),
              blurRadius: 12.0,
            ),
          ],
        ),

        //@@@@ WHEN BUTTON IS PRESSED @@@@
        child: ElevatedButton(
          onPressed: _submit,
          child: Text(
            'Prisijungti',
          ),
          style: ElevatedButton.styleFrom(
              //COLOR OF THE TEXT INSIDE THE BUTTON
              onPrimary: Color(0xFFFFFFFF),
              shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(12.0),
              ),
              primary: Colors.transparent,
              textStyle: TextStyle(
                //Text inside button style
                fontSize: 16.0,
                fontWeight: FontWeight.w600,
                fontFamily: 'Sora',
              )),
        ));
  }
}

【问题讨论】:

  • 是否需要将按钮的文本设置为从TextFormField接收到的值或输入文本?

标签: flutter dart


【解决方案1】:

访问字段数据

底部的代码示例显示了访问电子邮件字段值的两种不同方法:

  • FormFieldState
  • TextEditingController

这两种方法不依赖于 Form 包装您的字段(尽管这样做通常很方便,为您提供了更多处理表单数据和显示验证错误的选项。)

为什么要使用Form

Form 小部件包装字段对于将多个字段作为一个组一起处理/操作非常有用,例如表单重置、验证和提交。

我们通过GlobalKey&lt;FormState&gt; 访问这些Form 函数,我们在声明它时将其提供给Form

      child: Form(
        key: formKey, // declared above as a field in our State object

例如,TextFormField 有一个 validator: 参数(接受一个函数)。如果我们的字段在 Form 内,我们可以要求 Form 调用所有验证器函数来“验证”我们的表单:

formKey.currentState.validate();

validator: 将显示您返回给它的任何非空字符串:

代码示例

import 'package:flutter/material.dart';

class FormValuesPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Form Values'),
      ),
      body: FormValuesExample(),
    );
  }
}

class FormValuesExample extends StatefulWidget {
  @override
  _FormValuesExampleState createState() => _FormValuesExampleState();
}

class _FormValuesExampleState extends State<FormValuesExample> {
  GlobalKey<FormState> formKey = GlobalKey<FormState>();
  GlobalKey<FormFieldState> emailFieldKey = GlobalKey();
  TextEditingController emailController = TextEditingController();

  @override
  void dispose() {
    emailController.dispose();
    super.dispose();
  }
  @override
  Widget build(BuildContext context) {
    return Padding(
      padding: EdgeInsets.symmetric(horizontal: 20),
      child: Form(
        key: formKey, // declared above as a field in our State object
        child: Column(
          mainAxisAlignment: MainAxisAlignment.spaceEvenly,
          children: [
            TextFormField(
              key: emailFieldKey,
              controller: emailController,
              decoration: InputDecoration(
                labelText: 'Email'
              ),
              validator: (val) => validateEmail(val),
            ),
            LoginButton(formKey: formKey, fieldKey: emailFieldKey, controller: emailController,)
          ],
        ),
      ),
    );
  }

  String validateEmail(String email) {
    if (email == null || email.isEmpty)
      return 'Email cannot be empty';
    return null;
  }
}

class LoginButton extends StatelessWidget {
  final GlobalKey<FormState> formKey;
  final GlobalKey<FormFieldState> fieldKey;
  final TextEditingController controller;

  LoginButton({this.formKey, this.fieldKey, this.controller});

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
        onPressed: () {
          formKey.currentState.validate();
          print('from FormFieldState ${fieldKey.currentState.value}');
          print('from controller: ${controller.text}');
        },
        child: Text('Submit'));
  }
}

【讨论】:

    【解决方案2】:

    您需要将它们包装在一个 Form 小部件中并传递密钥,例如:

    Form(
      key: _keyForm
      child: Column(
        children: <Widget>[
         EmailTextFieldForm(),
         PasswordTextFieldForm(),
         FormButton(),
       ],
     )
    )
    

    【讨论】:

      【解决方案3】:

      您需要将所有 TextFormFields 包装在一个表单中才能像这样得到它

      Column(
        children: [
          TextFormField(),
          ....
          TextFormField(),
      ])
      

      TextFormFields 可以被包装或移动到另一个小部件,只要它是窗体的子级。

      如果一切都在一个小部件中

      Form(
        child: 
           Column(
           children: [
             TextFormField(),
             ....
             TextFormField(),
             Button(
               onTap: () {},
             ),
      ])
      

      您需要将按钮包装在 Builder 中,以便树中当前元素的上下文可用

      Builder(
        builder: (context) => Button(
          onTap: () {},
        ),
      ),
      

      然后,您可以使用Form.of(context).validate()。该条目将在树中找到第一个表单并验证所有文本字段。

      这样你就应该这样出去

      Builder(
        builder: (context) => Button(
          onTap: () {
            Form.of(context).validate()
          },
        ),
      )
      

      如果按钮放置在单独的小部件中,则无需将其包装在 Builder 中,您可以简单地调用验证,因为您可以使用表单下方的上下文

      Button(
        onTap: () {
          Form.of(context).validate()
        },
      ),
      

      另外,您可以创建 GlobalKey

      并使用密钥进行验证。您可以传递密钥,例如,通过构造函数(如果需要)

      final _formKey = GlobalKey<FormState>();
      
      Form(
        key: _formKey
        child: Column(
          children: [
            TextFormField(),
            ....
            Button(
              onTap: () {
                _formKey.currentState!.validate ()
              }
            )
          ],
        ),
       )
      

      【讨论】:

        猜你喜欢
        • 2019-08-28
        • 2021-11-11
        • 1970-01-01
        • 2019-09-07
        • 2023-01-28
        • 2021-01-11
        • 2021-12-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多