[英]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:以下代码执行以下操作:
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.