Material design组件提供了两种输入框,分别是TextField和TextFormField。他们的作用都是使用户可以使用硬件键盘或屏幕键盘输入文本。
TextField
每当用户更改字段中的文本时,文本字段就会调用onChanged回调。如果用户已完成在字段中的键入(例如,通过按软键盘上的按钮),则文本字段将调用onSubmitted回调。
要控制在文本字段中显示的文本,就要使用controller。例如,要设置文本字段的初始值,请使用已经包含一些文本的controller。
默认情况下,TextField具有默认修饰,该修饰在TextField下方绘制分隔线。您可以使用decoration属性来控制装饰,例如,通过添加标签或图标。如果将decoration属性设置为null,则装饰将被完全删除。
如果装饰非空(这是默认值),则TextField要求其父节点是material widget。轻击TextField时,触发涟漪效果。
要将TextField与其他FormField集成到Form中,请考虑使用TextFormField。
TextFormField
TextFormField继承FormField包含一个TextField。TextFormField使得重置或验证多个字段变得更加容易。 要在没有表单的情况下使用,请将GlobalKey传递给构造函数,然后使用GlobalKey.currentState保存或重置表单字段。
指定controller后,TextEditingController.text定义initialValue。 如果FormField是延迟构造其子级的滚动容器的一部分,例如ListView或CustomScrollView,则应指定一个控制器。 控制器的生存期应由滚动容器的有状态widget父节点管理。
如果未指定控制器,则可以使用initialValue为自动生成的控制器提供初始值。
Controller
我们在来看看controller,通过它可以设置/获取编辑框的内容、选择编辑内容、监听编辑文本改变事件。大多数情况下我们都需要显式提供一个controller
来与文本框交互。如果没有提供controller
,则TextField
内部会自动创建一个。
class TextFieldPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
onChanged: (value) {
print("value $value");
},
decoration: InputDecoration(
labelText: "请输入用户名",
hintText: "我是暗示",
prefixIcon: Icon(Icons.person),
),
),
),
),
);
}
}
获取输入内容
- onChange 上面的代码中已经使用了这个办法
- controller
// 创建controller
TextEditingController _controller = TextEditingController();
_controller.text="我是默认值";
// 设置controller
TextField(
controller: _selectionController,
)
我们来看完整代码
class TextFieldPage extends StatelessWidget {
final TextEditingController _controller = TextEditingController();
TextFieldPage() {
_controller.addListener(() {
print(_controller.text);
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: TextField(
controller: _controller,
onChanged: (value) {
print("value $value");
},
decoration: InputDecoration(
labelText: "请输入用户名",
hintText: "我是暗示",
prefixIcon: Icon(Icons.person),
),
),
),
),
);
}
}
两种方式相比,onChanged
是专门用于监听文本变化,而controller
的功能却多一些,比如设置默认值、选择文本等。
对于输入框,我们在开发中可能最关心的还是输入的内容是否合法,比如电话号是否合法,邮箱是否合法等。这个时候就要用到我们的表单Form 和 TextFormField了。
Form组件主要属性
属性 | 类型 | 说明 |
key | Key | Widget树中的key |
autovalidate | bool | 自动提交表单 |
child | Widget | 组件的child |
onChanged | VoidCallback |
当FormField值改变回调函数 |
... | ... | ... |
TextFormField主要属性
属性 | 类型 | 说明 |
key | Key | Widget树中的key |
autovalidate | bool | 自动验证 |
initialValue | T | 初始值 |
onSaved | FormFieldSetter<T> | Form调用保存方法回调 |
validator | FormFieldValidator<T> | Form表单验证 |
... | ... | ... |
要想获得表单,我们需要设置一个全局类型的key,通过这个key的属性来获取表单对象。关于key,我会在另外的文章中介绍。
class TextFieldPage extends StatelessWidget {
final GlobalKey<FormState> _globalKey = GlobalKey<FormState>();
@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
children: [
Form(
key: _globalKey,
child: TextFormField(
onSaved: (value) {
print("onSaved $value");
},
validator: (value) {
print("onSaved $value");
return value.length < 4 ? "长度不够" : null;
},
decoration: InputDecoration(
labelText: "请输入用户名",
hintText: "我是暗示",
prefixIcon: Icon(Icons.person),
),
),
),
RaisedButton(
child: Text('登陆'),
onPressed: () {
if (_globalKey.currentState.validate()) {
print('登陆成功');
}
},
),
],
),
),
);
}
}
整理一下,这里使用了Form,FormField,FormState
Form
继承自StatefulWidget
对象,它对应的状态类为FormState。
FormState
为Form
的State
类,可以通过Form.of()
或GlobalKey
获得。我们可以通过它来对Form
的子FormField
进行统一操作。FormField
是一个抽象类,定义几个属性,FormState
内部通过它们来完成操作。TextFormField继承
FormField。也是TextField
的一个包装类,所以除了FormField
定义的属性之外,它还包括TextField
的属性。
值得注意的是,如果使用Form.of()来获得FormState需要在Form的子节点中,包含一层Builder参数,此时返回的context才是可以获取到父节点的context。
总结:今天介绍了如何使用TextField或者Form加TextFormField来实现输入框功能,controller以及一些基本的回调函数,还要注意使用Form的表单的获取方式等。接下来的文章会继续将常用Widget逐一介绍,在最后的系列中,会公开一个商业级的项目,感兴趣的小伙伴关注。如果您在阅读过程中发现错误,请及时留言给我,我会第一时间改正。也欢迎大家一切交流,共同进步,感谢支持!