简体   繁体   English

在 Flutter 中,如何在表单外(即提交按钮下方)输出 TextFormField 验证器文本?

[英]In Flutter, how do you output TextFormField validator text outside the form (i.e. below submit button)?

I've written sample code that displays a message if user clicks on login button, when there is no string inside the TextFormField.我编写了示例代码,当 TextFormField 中没有字符串时,如果用户单击登录按钮,则会显示一条消息。 It will display a message below the TextFormField alerting the user to enter an email.它将在 TextFormField 下方显示一条消息,提醒用户输入电子邮件。 What I want to be able to do is display that message, somewhere else, perhaps below the login button.我希望能够做的是在其他地方显示该消息,也许在登录按钮下方。

Ideally, I have a login and password text field, and instead of displaying the message below each text field, I want to display the message below the login button.理想情况下,我有一个登录名和密码文本字段,而不是在每个文本字段下方显示消息,我想在登录按钮下方显示消息。 Any help would be appreciated!任何帮助,将不胜感激! I looked into text controllers, but don't know how to implement so that if the validator passes with no message, it keeps the widgets the same heights, but only expands the height when validator fails displays message.我查看了文本控制器,但不知道如何实现,以便如果验证器在没有消息的情况下通过,它会使小部件保持相同的高度,但仅在验证器失败时才扩展高度显示消息。

import 'package:flutter/material.dart';

final Color darkBlue = Color.fromARGB(255, 18, 32, 47);

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: TextFieldExample(),
        ),
      ),
    );
  }
}

class TextFieldExample extends StatefulWidget {
  @override
  _TextFieldExampleState createState() => _TextFieldExampleState();
}

class _TextFieldExampleState extends State<TextFieldExample> {
  final _formKey = GlobalKey<FormState>();
  String email = '';

  Widget build(BuildContext context) {
    return Container(
      margin: EdgeInsets.symmetric(vertical: 5),
      padding: EdgeInsets.symmetric(horizontal: 15),
      decoration: BoxDecoration(borderRadius: BorderRadius.circular(29)),
      child: Form(
        key: _formKey,
        child: Column(children: <Widget>[
          TextFormField(
            validator: (value) => value.isEmpty ? 'Enter an email' : null,
            onChanged: (value) {
              setState(() => email = value);
            },
            decoration:
                InputDecoration(icon: Icon(Icons.person), hintText: "Email"),
          ),
          Container(
              margin: EdgeInsets.symmetric(vertical: 5),
              child: ClipRRect(
                  borderRadius: BorderRadius.circular(29),
                  child: RaisedButton(
                      padding: EdgeInsets.symmetric(vertical: 10),
                      onPressed: () async {
                        if (_formKey.currentState.validate()) {
                          //sign in;
                        }
                      },
                      child: Text("Login")))),
        ]),
      ),
    );
  }
}

定位示例

Thanks to the help of LOfG ( In Flutter, I'm trying to dynamically update my column widget based on Text Controller. How do I do this? ), I got inspired with the answer.感谢 LOfG 的帮助( 在 Flutter 中,我正在尝试基于文本控制器动态更新我的列小部件。我该怎么做? ),我从答案中得到了启发。

The following code does the following:以下代码执行以下操作:

  • Uses StreamBuilder to rebuild with every new event使用 StreamBuilder 重建每个新事件
  • Displays message underneath the login button only if validation fails, otherwise return empty container仅当验证失败时才在登录按钮下方显示消息,否则返回空容器
  • When user clicks on the username or password, the message disappears if not empty当用户点击用户名或密码时,如果不为空则消息消失
  • Uses snapshot.data to log in user (can use Provider with FirebaseAuth here)使用 snapshot.data 登录用户(可以在此处使用 Provider 和 FirebaseAuth)

The reason why I wanted this functionality, is to display error messages at a certain location, rather than in the text fields.我想要这个功能的原因是在特定位置显示错误消息,而不是在文本字段中。

import 'package:flutter/material.dart';
import 'dart:async';

final Color darkBlue = Color.fromARGB(255, 18, 32, 47);

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: TextFieldExample(),
        ),
      ),
    );
  }
}

class TextFieldExample extends StatefulWidget {
  @override
  _TextFieldExampleState createState() => _TextFieldExampleState();
}

class _TextFieldExampleState extends State<TextFieldExample> {
  @override
  void dispose() {
    _username.close();
    _password.close();
    super.dispose();
  }

  String validatorMessage;
  bool validate = false; //will be true if the user clicked in the    login button
  final _username = StreamController<String>(); //stream to   validate   the text
  final _password = StreamController<String>();

  Widget build(BuildContext context) {
    return Scaffold(
      body: Container(
          margin: EdgeInsets.symmetric(vertical: 5),
          padding: EdgeInsets.symmetric(horizontal: 15),
          decoration: BoxDecoration(
            borderRadius: BorderRadius.circular(29),
          ),
          //expose streambuilder to the column widget to use on multiple widgets
          child: StreamBuilder<String>(
              initialData: '',
              stream: _username.stream,
              builder: (context, usernameSnapshot) {
                return StreamBuilder<String>(
                    initialData: '',
                    stream: _password.stream,
                    builder: (context, passwordSnapshot) {
                      return Column(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: <Widget>[
                          TextField(
                            onChanged: _username.add, //everytime the text changes a new value will be added to the stream
                            decoration: InputDecoration(
                              icon: Icon(Icons.person),
                              hintText: "Email",
                            ),
                          ),
                          TextField(
                            obscureText: true,
                            onChanged: _password.add, //everytime the text changes a new value will be added to the stream
                            decoration: InputDecoration(
                              icon: Icon(Icons.visibility),
                              hintText: "Password",
                            ),
                          ),
                          Container(
                            margin: EdgeInsets.symmetric(vertical: 5),
                            child: ClipRRect(
                              borderRadius: BorderRadius.circular(29),
                              child: RaisedButton(
                                padding: EdgeInsets.symmetric(vertical: 10),
                                //when user presses button, validate turns to true and we check snapshots to get the data for the entries
                                onPressed: () async {
                                  if (usernameSnapshot.data.isNotEmpty && passwordSnapshot.data.isNotEmpty) {
                                    try {
                                      //sign in with usernameSnapshot.data and passwordSnapshot.data
                                    } catch (e) {
                                      print(e);
                                    }
                                    validate = true;
                                  } else {
                                    setState(() {
                                      validate = true;
                                    });
                                  }
                                },
                                child: Text("Login"),
                              ),
                            ),
                          ),
                          if (usernameSnapshot.data.isEmpty &&validate == true) //checking the stream and if the user clicked in the button
                            Container(
                              alignment: Alignment.center,
                              child: Text(
                                'Check your e-mail and password.',
                                style: TextStyle(
                                  color: Colors.red,
                                ),
                              ),
                            )
                          else
                            Container()
                        ],
                      );
                    });
              })),
    );
  }
}

小部件

Consider using a Row instead of Column考虑使用Row而不是Column

import 'package:flutter/material.dart';
    
    final Color darkBlue = Color.fromARGB(255, 18, 32, 47);
    
    void main() {
      runApp(MyApp());
    }
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          theme: ThemeData.dark().copyWith(scaffoldBackgroundColor: darkBlue),
          debugShowCheckedModeBanner: false,
          home: Scaffold(
            body: Center(
              child: TextFieldExample(),
            ),
          ),
        );
      }
    }
    
    class TextFieldExample extends StatefulWidget {
      @override
      _TextFieldExampleState createState() => _TextFieldExampleState();
    }
    
    class _TextFieldExampleState extends State<TextFieldExample> {
      final _formKey = GlobalKey<FormState>();
      String email = '';
    
      Widget build(BuildContext context) {
        return Container(
          margin: EdgeInsets.symmetric(vertical: 5),
          padding: EdgeInsets.symmetric(horizontal: 15),
          decoration: BoxDecoration(borderRadius: BorderRadius.circular(29)),
          child: Form(
            key: _formKey,
            child: Row(children: <Widget>[
              Flexible(
    
                child: TextFormField(
                  validator: (value) => value.isEmpty ? 'Enter an email' : null,
                  onChanged: (value) {
                    setState(() => email = value);
                  },
                  decoration:
                  InputDecoration(icon: Icon(Icons.person), hintText: "Email"),
                ),
              ),
              Expanded(
                flex: 0,
                child: Container(
                  margin: EdgeInsets.symmetric(vertical: 5),
                  child: ClipRRect(
                      borderRadius: BorderRadius.circular(29),
                      child: RaisedButton(
                          padding: EdgeInsets.symmetric(vertical: 10),
                          onPressed: () async {
                            if (_formKey.currentState.validate()) {
                              //sign in;
                            }
                          },
                          child: Text("Login")))),)
    
            ]),
          ),
        );
      }
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 flutter - 如何将 textformfield 提交到注册按钮? - flutter - how to submit textformfield to a sign up button? 当提交按钮在表单之外时,如何使用Bootstrap 3表单验证? - How do I use Bootstrap 3 form validation when submit button is outside the form? Flutter TextFormField 验证器 - Flutter TextFormField validator 如何更改 Textformfield 验证文本的 position? Flutter - How can I change the position of the Textformfield validation text ? Flutter 如何验证表单内的输入并在表单外提交按钮 - How to validate inputs inside form and submit button outside the form jQuery 验证器帮助:如何使用“提交”超链接而不是“提交”按钮并让 jQuery 验证器验证? - jQuery validator assistance: How can I use a “submit” hyperlink instead of a “submit” button and have jQuery validator validate? 如何在提交按钮位于此表单之外时使用angularJs验证表单? - How to validate a form when the submit button is outside of this form, with angularJs? 如何重新定位表单验证器错误 - How do I reposition a Form Validator error 我如何创建一个jQuery表单验证器 - How do I creat a jquery form validator Flutter Textformfield 验证器将最后一个 TextFormfield 集中在验证错误上,而不是第一个 - Flutter Textformfield validator Focuses Last TextFormfield on validation error instead of first
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM