3.7 输入框和表单
输入框有TextField、带有iOS风格的CupertinoTextField,还有表单form.
3.7.1 TextField
TextField默认带有下划线,无边框的,属性InputDecoration可以设置默认文字,当编辑状态,文字已动画形式上浮至左上角,这是其他输入框所没有的。其他的看下属性:
const TextField({
...
this.controller,
this.focusNode,
this.decoration = const InputDecoration(),
TextInputType keyboardType,
this.textInputAction,
this.style,
this.textAlign = TextAlign.start,
this.textAlignVertical,
this.textDirection,
this.showCursor,
this.autofocus = false,
this.obscureText = false,
this.enableSuggestions = true,
this.maxLines = 1,
this.minLines,
this.expands = false,
this.maxLength,
this.onChanged,
this.onEditingComplete,
this.onSubmitted,
this.inputFormatters,
this.enabled,
this.cursorWidth = 2.0,
this.cursorRadius,
this.cursorColor,
...
})
controller可以获取文字和设置文字,focusNode获取焦点keyboardType键盘类型textInputAction输入键盘右下角的键onChanged当textField的value变化回调函数onSubmitted提交按键obscureTexttrue则显示原点,否则显示原文字cursorWidth光标宽度cursorRadius光标圆圈半径cursorColor光标颜色
textInputAction有多个值,具体见下表格:
| textInputAction | 备注 |
|---|---|
none |
Android是IME_ACTION_NONE,iOS没有 |
unspecified |
Android's IME_ACTION_UNSPECIFIED,iOS 是return |
done |
Android's IME_ACTION_DONE iOS是done |
go |
android and iOS 都是go |
search |
android and ios is Search |
send |
android and ios is send |
next |
android and ios is next |
previous |
iOS没有,Android's IME_ACTION_PREVIOUS |
continueAction |
Android没有,iOS上是contion |
join |
android and ios is join |
route |
android没有,ios is route |
emergencyCall |
android没有,ios is Emergency Call |
newline |
android and ios都没有,只是方便开发人员调试 |
例子:
_focusNode = new FocusNode();
_editingController = new TextEditingController();
_field = TextField(
focusNode: _focusNode,
onChanged: (v) {
setState(() {});
},
onSubmitted: (v) {
_focusNode.unfocus();
},
controller: _editingController,
obscureText: false, //是否是密码
decoration: InputDecoration(hintText: '手机号', labelText: '手机号'),
keyboardType: TextInputType.number,
);
Column(
children: <Widget>[
Text('TextField'),
_field,
Text(_editingController.value.text),
],
)
效果如下:

iOS-style的组件CupertinoTextField,属性和TextField基本一致;
例子:
_editingController2 = new TextEditingController();
_focusNode2 = new FocusNode();
_cupertinoTextField = CupertinoTextField(
focusNode: _focusNode2,
controller: _editingController2,
placeholder: '密码',
prefix: Icon(Icons.lock),
textInputAction: TextInputAction.go,
obscureText: true,
);
Column(
children: <Widget>[
SizedBox(
height: 30,
),
Text('CupertinoTextField'),
_cupertinoTextField,
],
)
效果:

监听文本变化
_editingController = new TextEditingController()
..addListener(() {
print("${_editingController.value.text}");
});
或者
TextField(
focusNode: _focusNode,
onChanged: (v) {
print('onChange$v');
},
controller: _editingController,
...
);
收键盘
TextField(
focusNode: _focusNode,
);
/// 收键盘
_focusNode.unfocus();
收键盘之前必须在初始化的时候赋值给TextField,另外官方还提供了编辑下一个textField,当下边没有可以提供编辑的textField则进行书键盘操作,有的话则跳至下一个textField.
_focusNode.focusInDirection(TraversalDirection.down);
3.7.2 Form
Form更新数据和获取数据需要使用_globalKey获取当前的State。
例子:
Form(
key: _globalKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextFormField(
decoration: const InputDecoration(
hintText: 'Enter your email',
),
validator: (value) {
if (value.isEmpty) {
return 'Please enter some text';
}
return null;
},
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: RaisedButton(
onPressed: () {
// Validate will return true if the form is valid, or false if
// the form is invalid.
if (_globalKey.currentState.validate()) {
// Process data.
}
},
child: Text('Submit'),
),
),
],
),
)

Form子树中可以是多个TextFormField,每个可以单个校验,所有的都校验过了,FormState才是校验通过的,多用于多输入校验。那么我们写一个登陆的简单校验。
例子:
_form = Form(
key: _globalKey,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
TextFormField(
decoration: const InputDecoration(
hintText: 'Enter your email', icon: Icon(Icons.mail)),
validator: (value) {
if (value.isEmpty) {
return 'Please enter some text';
}
return null;
},
),
TextFormField(
controller: _editingController3,
decoration: InputDecoration(
labelText: "密码", hintText: "您的登录密码", icon: Icon(Icons.lock)),
obscureText: true,
//校验密码
validator: (v) {
return v.trim().length > 5 ? null : "密码不能少于6位";
}),
Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: RaisedButton(
onPressed: () {
// Validate will return true if the form is valid, or false if
// the form is invalid.
if (_globalKey.currentState.validate()) {
// Process data.
print('校验通过');
}
setState(() {
_done = _globalKey.currentState.validate();
});
},
child: Text('Submit'),
),
),
],
),
);
