Flutter-表单Widget
1.TextField的使用
1.1. TextField的介绍
TextField用于接收用户的文本输入,它提供了非常多的属性,我们来看一下源码:
const TextField({
Key key,
this.controller,
this.focusNode,
this.decoration = const InputDecoration(),
TextInputType keyboardType,
this.textInputAction,
this.textCapitalization = TextCapitalization.none,
this.style,
this.strutStyle,
this.textAlign = TextAlign.start,
this.textAlignVertical,
this.textDirection,
this.readOnly = false,
ToolbarOptions toolbarOptions,
this.showCursor,
this.autofocus = false,
this.obscureText = false,
this.autocorrect = true,
this.maxLines = 1,
this.minLines,
this.expands = false,
this.maxLength,
this.maxLengthEnforced = true,
this.onChanged,
this.onEditingComplete,
this.onSubmitted,
this.inputFormatters,
this.enabled,
this.cursorWidth = 2.0,
this.cursorRadius,
this.cursorColor,
this.keyboardAppearance,
this.scrollPadding = const EdgeInsets.all(20.0),
this.dragStartBehavior = DragStartBehavior.start,
this.enableInteractiveSelection = true,
this.onTap,
this.buildCounter,
this.scrollController,
this.scrollPhysics,
})
我们来学习几个比较常见的属性:
- 一些属性比较简单:keyboardType键盘的类型,style设置样式,textAlign文本对齐方式,maxLength最大显示行数等等;
- decoration:用于设置输入框相关的样式
- icon:设置左边显示的图标
- labelText:在输入框上面显示一个提示的文本
- hintText:显示提示的占位文字
- border:输入框的边框,默认底部有一个边框,可以通过InputBorder.none删除掉
- filled:是否填充输入框,默认为false
- fillColor:输入框填充的颜色
- controller:
- onChanged:监听输入框内容的改变,传入一个回调函数
- onSubmitted:点击键盘中右下角的down时,会回调的一个函数
1.2. TextField的样式以及监听
import 'package:flutter/material.dart';
main(List<String> args) {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("HelloWorld"),
),
body: MyHomeBody(),
),
);
}
}
class MyHomeBody extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(20),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextFieldDemo()
],
),
);
}
}
class TextFieldDemo extends StatefulWidget {
@override
_TextFieldDemoState createState() => _TextFieldDemoState();
}
class _TextFieldDemoState extends State<TextFieldDemo> {
@override
Widget build(BuildContext context) {
return TextField(
decoration: InputDecoration(
icon: Icon(Icons.people),
labelText: "username",
hintText: "请输入用户名",
border: InputBorder.none,
filled: true,
fillColor: Colors.lightGreen
),
onChanged: (value){
print("onChange:$value");
},
onSubmitted: (value){
print("onSubmitted:$value");
} ,
);
}
}
image.png
1.3. TextField的controller
我们可以给TextField添加一个控制器(Controller),可以使用它设置文本的初始值,也可以使用它来监听文本的改变
事实上,如果我们没有为TextField提供一个Controller,那么会Flutter会默认创建一个TextEditingController的,这个结论可以通过阅读源码得到:
override
void initState() {
super.initState();
// ...其他代码
if (widget.controller == null)
_controller = TextEditingController();
}
我们也可以自己来创建一个Controller控制一些内容:
class _TextFieldDemoState extends State<TextFieldDemo> {
final textEditingController = TextEditingController();
@override
void initState() {
super.initState();
// 1.设置默认值
textEditingController.text = "Hello World";
// 2.监听文本框
textEditingController.addListener(() {
print("textEditingController:${textEditingController.text}");
});
}
// ...省略build方法
}
image.png
2. Form表单的使用
在我们开发注册、登录页面时,通常会有多个表单需要同时获取内容或者进行一些验证,如果对每一个TextField都分别进行验证,是一件比较麻烦的事情。
做过前端的开发知道,我们可以将多个input标签放在一个form里面,Flutter也借鉴了这样的思想:我们可以通过Form对输入框进行分组,统一进行一些操作。
2.1. Form表单的基本使用
Form表单也是一个Widget,可以在里面放入我们的输入框。
但是Form表单中输入框必须是FormField类型的
- 我们查看刚刚学过的TextField是继承自StatefulWidget,并不是一个FormField类型;
- 我们可以使用TextFormField,它的使用类似于TextField,并且是继承自FormField的;
我们通过Form的包裹,来实现一个注册的页面:
import 'package:flutter/material.dart';
main(List<String> args) {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("HelloWorld"),
),
body: MyHomeBody(),
),
);
}
}
class MyHomeBody extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(20),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FormDemo()
],
),
);
}
}
class FormDemo extends StatefulWidget {
@override
_FormDemoState createState() => _FormDemoState();
}
class _FormDemoState extends State<FormDemo> {
@override
Widget build(BuildContext context) {
return Form(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextFormField(
decoration: InputDecoration(
icon: Icon(Icons.people),
labelText: "用户名或手机号"
),
),
TextFormField(
obscureText: true,
decoration: InputDecoration(
icon: Icon(Icons.lock),
labelText: "密码"
),
),
SizedBox(height: 16,),
Container(
width: double.infinity,
height: 44,
child: RaisedButton(
color: Colors.lightGreen,
child: Text("注册",style: TextStyle(fontSize: 20,color: Colors.white),),
onPressed: (){
print("点击了注册按钮");
},
),
),
],
),
);
}
}
image.png
2.2. 保存和获取表单数据
有了表单后,我们需要在点击注册时,可以同时获取和保存表单中的数据,怎么可以做到呢?
- 1)需要监听注册按钮的点击,在之前我们已经监听的onPressed传入的回调中来做即可。(当然,如果嵌套太多,我们待会儿可以将它抽取到一个单独的方法中)
- 2)监听到按钮点击时,同时获取用户名和密码的表单信息。
如何同时获取用户名和密码的表单信息?
- 如果我们调用Form的State对象的save方法,就会调用Form中放入的TextFormField的onSave回调:
TextFormField(
decoration: InputDecoration(
icon: Icon(Icons.people),
labelText: "用户名或手机号"
),
onSaved: (value) {
print("用户名:$value");
},
),
但是,我们有没有办法可以在点击按钮时,拿到 Form对象 来调用它的save方法呢?
知识点:在Flutter如何可以通过一个引用获取一个StatefulWidget的State对象呢?
答案:通过绑定一个GlobalKey即可。
import 'package:flutter/material.dart';
main(List<String> args) {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("HelloWorld"),
),
body: MyHomeBody(),
),
);
}
}
class MyHomeBody extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(20),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
FormDemo()
],
),
);
}
}
class FormDemo extends StatefulWidget {
@override
_FormDemoState createState() => _FormDemoState();
}
class _FormDemoState extends State<FormDemo> {
final registerFormKey = GlobalKey<FormState>();
String username,password;
void registerForm(){
registerFormKey.currentState.save();
print("username:$username password:$password");
}
@override
Widget build(BuildContext context) {
return Form(
key: registerFormKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
TextFormField(
decoration: InputDecoration(
icon: Icon(Icons.people),
labelText: "用户名或手机号"
),
onSaved: (value){
this.username = value;
},
),
TextFormField(
obscureText: true,
decoration: InputDecoration(
icon: Icon(Icons.lock),
labelText: "密码"
),
onSaved: (value){
this.password = value;
},
),
SizedBox(height: 16,),
Container(
width: double.infinity,
height: 44,
child: RaisedButton(
color: Colors.lightGreen,
child: Text("注册",style: TextStyle(fontSize: 20,color: Colors.white),),
onPressed: registerForm,
),
),
],
),
);
}
}
image.png
2.3. 验证填写的表单数据
在表单中,我们可以添加验证器,如果不符合某些特定的规则,那么给用户一定的提示信息
比如我们需要账号和密码有这样的规则:账号和密码都不能为空。
按照如下步骤就可以完成整个验证过程:
- 1)为TextFormField添加validator的回调函数;
-
2)调用Form的State对象的validate方法,就会回调validator传入的函数;
image.png
也可以为TextFormField添加一个属性:autovalidate
-
不需要调用validate方法,会自动验证是否符合要求;
image.png
学习内容来自Flutter从入门到实战