获取多个文本字段值的最佳方法

Amo*_*kar 15 dart flutter

我正在制作一个数据收集应用程序,它有多个TextFields,比如超过 12 个。我正在使用一个表单键来验证所有这些。我想要所有文本字段的值,以便我可以将它们保存到 firestore。我该怎么做呢?这是我的代码:

import 'package:flutter/material.dart';

class MainForm extends StatefulWidget {
  @override
  _MainFormState createState() => _MainFormState();
}

class _MainFormState extends State<MainForm> {
  final _formKey = GlobalKey<FormState>();

  @override
  Widget build(BuildContext context) {
    return Center(
      child: SingleChildScrollView(
        child: Form(
          key: _formKey,
          child: Column(
            children: <Widget>[
              Text('Enter information about PG Owner'),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: TextField(
                  autofocus: true,
                  textCapitalization: TextCapitalization.words,
                  textAlignVertical: TextAlignVertical.center,
                  onTap: () {},
                  decoration: InputDecoration(
                      prefixIcon: Icon(Icons.face),
                      labelText: 'Enter Name of Owner',
                      border: OutlineInputBorder()),
                ),
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: TextFormField(
                  validator: (value) {
                    if (value.length < 15) {
                      return 'Address seems very short!';
                    }
                    return null;
                  },
                  keyboardType: TextInputType.text,
                  decoration: InputDecoration(
                      prefixIcon: Icon(Icons.room),
                      labelText: 'Enter full address of Owner',
                      border: OutlineInputBorder()),
                ),
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: TextFormField(
                  keyboardType: TextInputType.number,
                  validator: (value) {
                    if (value.length < 9) {
                      return 'Phone number must be 9 digits or longer';
                    }
                    return null;
                  },
                  decoration: InputDecoration(
                      prefixIcon: Icon(Icons.phone),
                      labelText: 'Phone number of Owner',
                      border: OutlineInputBorder()),
                ),
              ),
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: TextFormField(
                  validator: (value) {
                    if (value.isEmpty) {
                      return 'Please enter a valid email address';
                    }
                    if (!value.contains('@')) {
                      return 'Email is invalid, must contain @';
                    }
                    if (!value.contains('.')) {
                      return 'Email is invalid, must contain .';
                    }
                    return null;
                  },
                  keyboardType: TextInputType.emailAddress,
                  decoration: InputDecoration(
                      prefixIcon: Icon(Icons.mail_outline),
                      labelText: 'Enter Email',
                      border: OutlineInputBorder()),
                ),
              ),
              )
            ],
          ),
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

更新:我知道从 a 获取值的正确方法(我已经阅读了文档)TextField是通过创建控制器。但是,就我而言,有 14TextField秒需要我创建 14 个控制器。有没有更好的方法来做到这一点?

use*_*321 20

您可以在以下代码中使用类似的内容:

_formKey.currentState.save(); 在每个 textFormField 项上调用onSaved(),它将值分配给所有字段,您可以根据需要使用它们。尝试使用_formKey.currentState.save(); 就在_formKey.currentState.validate()被评估为 true 之后。

表单代码如下所示:

String contactNumber;
String pin;
return Form(
  key: _formKey,
  child: Column(
    children: <Widget>[
      TextFormField(
        onSaved: (String value){contactNumber=value;},
        keyboardType: TextInputType.phone,
        inputFormatters: [WhitelistingTextInputFormatter.digitsOnly],
        maxLength: 10,
        decoration: InputDecoration(
            labelText: "Enter Your Mobile Number",
            hintText: "Number",
            icon: Icon(Icons.phone_iphone)),
        validator: (value) {
          if (value.isEmpty || value.length < 10) {
            return 'Please Enter 10 digit number';
          }
          return null;
        },
      ),
      TextFormField(
        onSaved: (String value){pin=value;},
        keyboardType: TextInputType.phone,
        inputFormatters: [WhitelistingTextInputFormatter.digitsOnly],
        maxLength: 10,
        decoration: InputDecoration(
            labelText: "Enter Your PIN",
            hintText: "Number",
            icon: Icon(Icons.lock)),
        validator: (value) {
          if (value.isEmpty || value.length < 6) {
            return 'Please Enter 6 digit PIN';
          }
          return null;
        },
      ),
      Padding(
        padding: const EdgeInsets.symmetric(vertical: 16.0),
        child: RaisedButton(
            color: Colors.black,
            textColor: Colors.white,
            onPressed: () {
              if (_formKey.currentState.validate()) {
                ***_formKey.currentState.save();***
                bloc.loginUser(contactNumber, pin);
              }
            },
            child: Text('Login' /*style: TextStyle(fontSize: 30),*/)),
      )
    ],
  ),
);
Run Code Online (Sandbox Code Playgroud)

  • 这个答案似乎不错,但是什么是好方法..创建 onsaved 或有 textEditingControllers (2认同)

Nea*_*arl 12

我对 Flutter 让你自己处理表单值的方式不满意,你需要TextEditingController为每个字段创建一个实例,将其分配给controller并记住手动处理所有它们。这会导致大量样板代码并使其更容易出错:

final _formKey = GlobalKey<FormState>();
final controller1 = TextEditingController();
final controller2 = TextEditingController();
final controller3 = TextEditingController();

@override
void dispose() {
  super.dispose();
  controller1.dispose();
  controller2.dispose();
  controller3.dispose();
}

@override
Widget build(BuildContext context) {
  return Form(
    key: _formKey,
    child: Column(children: [
      TextFormField(controller: controller1),
      TextFormField(controller: controller2),
      TextFormField(
        controller: controller3,
        validator: (value) {
          if (value == null || value.isEmpty) {
            return 'Please enter some text';
          }
          return null;
        },
      ),
      ElevatedButton(
        onPressed: () {
          if (_formKey.currentState!.validate()) {
            final value1 = controller1.text;
            final value2 = controller2.text;
            final value3 = controller3.text;

            // do something with the form data
          }
        },
        child: const Text('Submit'),
      ),
    ]),
  );
}
Run Code Online (Sandbox Code Playgroud)

一种不太麻烦的方法是使用该flutter_form_builder包并替换TextFormFieldFormBuilderTextField旧 plain 的包装器小部件TextField您可以在此处查看所有支持的输入小部件。

您现在需要做的就是指定表单中每个字段的名称,并在_formKey.currentState?.value. 请参阅下面的示例:

final _formKey = GlobalKey<FormBuilderState>();

@override
Widget build(BuildContext context) {
  return FormBuilder(
    key: _formKey,
    child: Column(children: [
      FormBuilderTextField(name: 'field1'),
      FormBuilderTextField(name: 'field2'),
      FormBuilderTextField(
        name: 'field3',
        validator: FormBuilderValidators.required(
          context,
          errorText: 'Please enter some text',
        ),
      ),
      ElevatedButton(
        onPressed: () {
          _formKey.currentState.save();
          if (_formKey.currentState!.validate()) {
            final formData = _formKey.currentState?.value;
            // formData = { 'field1': ..., 'field2': ..., 'field3': ... }
            // do something with the form data
          }
        },
        child: const Text('Submit'),
      ),
    ]),
  );
}
Run Code Online (Sandbox Code Playgroud)


小智 6

我是通过类似的搜索来到这里的。找到的所有答案都不能满足我的需求,因此我编写了一个自定义解决方案。

  • 表单键
    final _signUpKey = GlobalKey<FormState>();
Run Code Online (Sandbox Code Playgroud)
  • 声明你的 TextEditingController
    final Map<String, TextEditingController> sigUpController = {
      'firstName': TextEditingController(),
      'lastName': TextEditingController(),
      'email': TextEditingController(),
      'phone': TextEditingController(),
      'password': TextEditingController(),
    };
Run Code Online (Sandbox Code Playgroud)
  • 像这样将控制器传递给 TextFormField
    Form(
      key: _signUpKey,
      child: Column(
        children: [
          TextFormField(
            controller: sigUpController['firstName'],
            validator: validator,
            autofocus: autofocus,
            keyboardType: TextInputType.text,
            style: const TextStyle(
              fontSize: 14,
            ),
            onTap: onTap,
            onChanged: onChanged,
            inputFormatters: [
              FilteringTextInputFormatter.allow(
                RegExp(r"[a-zA-Z]+|\s"),
              ),
            ],
          ),
          // define the other TextFormField here
          TextButton(
            onPressed: () {
              if (!_signUpKey.currentState!.validate()) {
                return;
              }
    
              // To get data I wrote an extension method bellow
              final data = sigUpController.data();
    
              print('data: $data'); // data: {firstName: John, lastName: Doe, email: example@email.com, phone: 0000000000, password: password}
            },
            child: const Text('submit'),
          )
        ],
      ),
    );
Run Code Online (Sandbox Code Playgroud)
  • 从 Map<String, TextEditingController> 获取数据的扩展方法
    extension Data on Map<String, TextEditingController> {
      Map<String, dynamic> data() {
        final res = <String, dynamic>{};
        for (MapEntry e in entries) {
          res.putIfAbsent(e.key, () => e.value?.text);
        }
        return res;
      }
    }
Run Code Online (Sandbox Code Playgroud)


MSA*_*ish 5

使用 TextFormField 中的控制器,您可以获取 TextFormField 的值。

TextEditingController emailEditingController = TextEditingController();
TextFormField(
  controller: emailEditingController,
  validator: (value) {
    if (value.isEmpty) {
      return 'Please enter a valid email address';
    }
    if (!value.contains('@')) {
      return 'Email is invalid, must contain @';
    }
    if (!value.contains('.')) {
      return 'Email is invalid, must contain .';
    }
    return null;
  },
  keyboardType: TextInputType.emailAddress,
  decoration: InputDecoration(
      prefixIcon: Icon(Icons.mail_outline),
      labelText: 'Enter Email',
      border: OutlineInputBorder()),
);
Run Code Online (Sandbox Code Playgroud)

获取价值,如:

String email=emailEditingController.text;
Run Code Online (Sandbox Code Playgroud)

更新答案

使用 onSubmitted 获取价值

onSubmitted: (String value){email=value;},
Run Code Online (Sandbox Code Playgroud)

  • 我了解“TextEditingController”,我的问题是我是否必须为每个“TextField”创建一个控制器?由于有这么多,我正在寻找是否有更方便的方法。 (2认同)
  • 这不应该是公认的答案:它没有显示如何避免为每个表单字段创建控制器:这是一种代码味道。 (2认同)

Gia*_*ode 5

您可以使用flutter_form_bloc,不需要创建任何内容TextEditingController,并且可以将业务逻辑与用户界面分开,此外还提供其他优点。

dependencies:
  flutter_bloc: ^0.21.0
  form_bloc: ^0.4.1
  flutter_form_bloc: ^0.3.0
Run Code Online (Sandbox Code Playgroud)
dependencies:
  flutter_bloc: ^0.21.0
  form_bloc: ^0.4.1
  flutter_form_bloc: ^0.3.0
Run Code Online (Sandbox Code Playgroud)