如何将用户的TextFormField输入传递给flutter中不同类的按钮

Posted

技术标签:

【中文标题】如何将用户的TextFormField输入传递给flutter中不同类的按钮【英文标题】:How to pass user's TextFormField input to a button in a different class in 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接收到的值或输入文本? 【参考方案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 ()
        
      )
    ],
  ),
 )

【讨论】:

以上是关于如何将用户的TextFormField输入传递给flutter中不同类的按钮的主要内容,如果未能解决你的问题,请参考以下文章

[译]TextField/TextFormField 如何显示/隐藏密码

如何在textformfield onchange值上修剪文本

如何将用户定义的类型作为输入传递给存储过程?

如何将用户输入从节点服务器传递到外部 api 调用?

如何重置 TextFormField 中的错误消息?

如何将局部变量传递给熊猫中的用户定义函数?