输入框及表单
Material
组件库中提供了输入框组件TextField
和表单组件Form
。下面我们分别介绍一下。
TextField
TextField
用于文本输入,它提供了很多属性,我们先简单介绍一下主要属性的作用,然后通过几个示例来演示一下关键属性的用法。
const TextField({
...
TextEditingController controller,
FocusNode focusNode,
InputDecoration decoration = const InputDecoration(),
TextInputType keyboardType,
TextInputAction textInputAction,
TextStyle style,
TextAlign textAlign = TextAlign.start,
bool autofocus = false,
bool obscureText = false,
int maxLines = 1,
int maxLength,
bool maxLengthEnforced = true,
ValueChanged<String> onChanged,
VoidCallback onEditingComplete,
ValueChanged<String> onSubmitted,
List<TextInputFormatter> inputFormatters,
bool enabled,
this.cursorWidth = 2.0,
this.cursorRadius,
this.cursorColor,
...
})
controller
:编辑框的控制器,通过它可以设置/获取编辑框的内容、选择编辑内容、监听编辑文本改变事件。大多数情况下我们都需要显式提供一个controller来与文本框交互。如果没有提供controller,则TextField内部会自动创建一个。focusNode
:用于控制TextField是否占有当前键盘的输入焦点。它是我们和键盘交互的一个句柄(handle)。InputDecoration
:用于控制TextField的外观显示,如提示文本、背景颜色、边框等。keyboardType
:用于设置该输入框默认的键盘输入类型,取值如下:-
text
文本输入键盘
-
-
multiline
多行文本,需和maxLines配合使用(设为null或大于1)
-
-
number
数字;会弹出数字键盘
-
-
phone
优化后的电话号码输入键盘;会弹出数字键盘并显示“* #”
-
-
datetime
优化后的日期输入键盘;Android上会显示“: -”
-
-
emailAddress
优化后的电子邮件地址;会显示“@ .”
-
-
url
优化后的url输入键盘; 会显示“/ .”
-
style
:正在编辑的文本样式。textAlign
: 输入框内编辑文本在水平方向的对齐方式。autofocus
: 是否自动获取焦点。obscureText
:是否隐藏正在编辑的文本,如用于输入密码的场景等,文本内容会用“•”替换。maxLines
:输入框的最大行数,默认为1;如果为null,则无行数限制。maxLength
和maxLengthEnforced
:maxLength
代表输入框文本的最大长度,设置后输入框右下角会显示输入的文本计数。maxLengthEnforced
决定当输入文本长度超过maxLength
时是否阻止输入,为true时会阻止输入,为false时不会阻止输入但输入框会变红。onChange
:输入框内容改变时的回调函数;注:内容改变事件也可以通过controller来监听。onEditingComplete
和onSubmitted
:这两个回调都是在输入框输入完成时触发,比如按了键盘的完成键(对号图标)或搜索键(🔍图标)。不同的是两个回调签名不同,onSubmitted回调是ValueChanged<String>类型,它接收当前输入内容做为参数,而onEditingComplete不接收参数。inputFormatters
:用于指定输入格式;当用户输入内容改变时,会根据指定的格式来校验。enable
:如果为false,则输入框会被禁用,禁用状态不接收输入和事件,同时显示禁用态样式(在其decoration中定义)。cursorWidth
、cursorRadius
和cursorColor
:这三个属性是用于自定义输入框光标宽度、圆角和颜色的。
例子
Column(
children: <Widget>[
TextField(
autofocus: true,
decoration: InputDecoration(
labelText: "用户名",
hintText: "用户名或邮箱",
prefixIcon: Icon(Icons.person)
),
),
TextField(
decoration: InputDecoration(
labelText: "密码",
hintText: "您的登录密码",
prefixIcon: Icon(Icons.lock)
),
obscureText: true,
),
],
);
控制焦点
焦点可以通过FocusNode
和FocusScopeNode
来控制,默认情况下,焦点由FocusScope
来管理,它代表焦点控制范围,可以在这个范围内可以通过FocusScopeNode
在输入框之间移动焦点、设置默认焦点等。我们可以通过FocusScope.of(context)
来获取Widget树中默认的FocusScopeNode
。下面看一个示例,在此示例中创建两个TextField
,第一个自动获取焦点,然后创建两个按钮:
- 点击第一个按钮可以将焦点从第一个
TextField
挪到第二个TextField
。 -
点击第二个按钮可以关闭键盘。
class FocusTestRoute extends StatefulWidget {
@override
_FocusTestRouteState createState() => new _FocusTestRouteState();
}
class _FocusTestRouteState extends State<FocusTestRoute> {
FocusNode focusNode1 = new FocusNode();
FocusNode focusNode2 = new FocusNode();
FocusScopeNode focusScopeNode;
@override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.all(16.0),
child: Column(
children: <Widget>[
TextField(
autofocus: true,
focusNode: focusNode1,//关联focusNode1
decoration: InputDecoration(
labelText: "input1"
),
),
TextField(
focusNode: focusNode2,//关联focusNode2
decoration: InputDecoration(
labelText: "input2"
),
),
Builder(builder: (ctx) {
return Column(
children: <Widget>[
RaisedButton(
child: Text("移动焦点"),
onPressed: () {
//将焦点从第一个TextField移到第二个TextField
// 这是一种写法 FocusScope.of(context).requestFocus(focusNode2);
// 这是第二种写法
if(null == focusScopeNode){
focusScopeNode = FocusScope.of(context);
}
focusScopeNode.requestFocus(focusNode2);
},
),
RaisedButton(
child: Text("隐藏键盘"),
onPressed: () {
// 当所有编辑框都失去焦点时键盘就会收起
focusNode1.unfocus();
focusNode2.unfocus();
},
),
],
);
},
),
],
),
);
}
}
监听焦点状态改变事件
FocusNode
继承自ChangeNotifier
,通过FocusNode
可以监听焦点的改变事件,如:
...
// 创建 focusNode
FocusNode focusNode = new FocusNode();
...
// focusNode绑定输入框
TextField(focusNode: focusNode);
...
// 监听焦点变化
focusNode.addListener((){
print(focusNode.hasFocus);
});
自定义样式
虽然我们可以通过decoration
属性来定义输入框样式,下面以自定义输入框下划线颜色为例来介绍一下:
TextField(
decoration: InputDecoration(
labelText: "请输入用户名",
prefixIcon: Icon(Icons.person),
// 未获得焦点下划线设为灰色
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.grey),
),
//获得焦点下划线设为蓝色
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.blue),
),
),
),
隐藏下划线
通过Container
去嵌套定义样式,直接隐藏掉TextField
本身的下划线。如:
Container(
child: TextField(
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: "Email",
hintText: "电子邮件地址",
prefixIcon: Icon(Icons.email),
border: InputBorder.none //隐藏下划线
)
),
decoration: BoxDecoration(
// 下滑线浅灰色,宽度1像素
border: Border(bottom: BorderSide(color: Colors.grey[200], width: 1.0))
),
)
通过这种组件组合的方式,也可以定义背景圆角等。一般来说,优先通过decoration
来自定义样式,如果decoration
实现不了,再用widget组合的方式。