Flutter入门笔记系列文章部分内容来源于《Flutter 实战》,如有侵权请联系删除!
Material组件库中为我们提供了输入框组件TextField
。不管是Web端还是移动端开发,输入框都是最常用的组件之一,因此掌握输入框的使用显得尤为重要。
一、属性介绍
TextField属性比较多,本文只介绍其中比较常用的属性,更多属性请查阅SDK或官方文档。
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.enableSuggestions = 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,
})
controller
:编辑框的控制器,通过它可以设置/获取编辑框的内容、选择编辑内容、监听编辑文本改变事件。大多数情况下我们都需要显式提供一个controller
来与文本框交互。如果没有提供controller
,则TextField
内部会自动创建一个。focusNode
:用于控制TextField
是否占有当前键盘的输入焦点。它是我们和键盘交互的一个句柄(handle)。InputDecoration
:用于控制TextField
的外观显示,如提示文本、背景颜色、边框等。keyboardType
:用于设置该输入框默认的键盘输入类型,取值如下:
TextInputType枚举值 | 含义 |
---|---|
text | 文本输入键盘 |
multiline | 多行文本,需和maxLines配合使用(设为null或大于1) |
number | 数字,会弹出数字键盘 |
phone | 优化后的电话号码输入键盘;会弹出数字键盘并显示“* #” |
datetime | 优化后的日期输入键盘;Android上会显示“: -” |
emailAddress | 优化后的电子邮件地址;会显示“@ .” |
url | 优化后的url输入键盘; 会显示“/ .” |
-
textInputAction
:键盘动作按钮图标(即回车键位图标),它是一个枚举值,有多个可选值,全部的取值列表读者可以查看API文档,下面是当值为TextInputAction.search
时,原生Android系统下键盘样式如图3-24所示: 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
:这三个属性是用于自定义输入框光标宽度、圆角和颜色的。
二、登录示例:手机号+密码
1、编写布局代码
TextField(
keyboardType: TextInputType.phone,
maxLines: 1,
autofocus: false,
cursorColor: Colors.blue,
maxLength: 11,
maxLengthEnforced: true,
focusNode: phoneFocusNode,
decoration: InputDecoration(
hintText: "请输入手机号码",
labelText: "手机号",
prefixIcon: Icon(Icons.phone),
// 未获得焦点下划线设为灰色
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.grey),
),
//获得焦点下划线设为蓝色
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.blue),
),
),
),
TextField(
keyboardType: TextInputType.text,
obscureText: true,
maxLines: 1,
autofocus: false,
cursorColor: Colors.blue,
focusNode: passwordFocusNode,
decoration: InputDecoration(
hintText: "请输入密码",
labelText: "密码",
prefixIcon: Icon(Icons.vpn_key),
// 未获得焦点下划线设为灰色
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.grey),
),
//获得焦点下划线设为蓝色
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.blue),
),
),
),
Padding(
padding: EdgeInsets.all(16),
child: RaisedButton(
child: Text("开始登录"),
onPressed: () {
//开始登录
}),
)
运行效果
2、获取输入内容
-
使用onChanged监听文本变化
最简单直接的方法是使用TextFile的onChanged属性监听输入框文本变化,从而获取到手机号和密码。
TextField(
……
onChanged: (text) {
print("phone=$text");
},
)
TextField(
……
onChanged: (text) {
print("password=$text");
},
)
运行效果
-
使用controller监听文本变化
controller使用步骤如下:
创建TextEditingController -> 设置TextFile的controller属性controller: phoneController,
-> 重写方法initState()监听文本变化。
class _MyHomePageState extends State<MyHomePage> {
bool checkboxState = false; //CheckBox状态
bool switchState = false; //Switch状态
void _incrementCounter() {
setState(() {
// This call to setState tells the Flutter framework that something has
// changed in this State, which causes it to rerun the build method below
// so that the display can reflect the updated values. If we changed
// _counter without calling setState(), then the build method would not be
// called again, and so nothing would appear to happen.
_counter++;
});
}
TextEditingController phoneController = TextEditingController();
TextEditingController passwordController = TextEditingController();
@override
initState(){
//监听输入改变
phoneController.addListener((){
//通过controller获取输入框内容
print("phone="+phoneController.text);
});
passwordController.addListener((){
//通过controller获取输入框内容
print("password="+passwordController.text);
});
}
……
}
设置TextField的controller属性
TextField(
……
controller: phoneController,
)
运行效果
以上两种方法都可以成功获取到用户输入的手机号和密码。两种方式相比,onChanged是专门用于监听文本变化,而controller的功能却多一些,除了能监听文本变化外,它还可以设置默认值、选择文本。因此我们应该根据实际需求选择最合适的方法。
三、控制输入框焦点
焦点可以通过FocusNode和FocusScopeNode来控制,默认情况下,焦点由FocusScope来管理,它代表焦点控制范围,可以在这个范围内可以通过FocusScopeNode在输入框之间移动焦点、设置默认焦点等。我们可以通过FocusScope.of(context) 来获取Widget树中默认的FocusScopeNode。
在上面登录的例子中可以看到TextField中有一个属性focusNode
,它的值是FocusNode。简单介绍一下FocusNode中几个比较常用的成员变量和方法:
-
hasFocus
判断当前Node是否拥有输入焦点 -
nextFocus()
焦点移动到下一个FocusNode -
previousFocus()
焦点移动到上一个FocusNode -
requestFocus([FocusNode node])
指定某个FocusNode获得焦点 -
unfocus({ bool focusPrevious = false })
从具有主要焦点的FocusNode上删除焦点,并取消所有未完成的聚焦请求。
如果[focusPrevious]为true,焦点将会被移至FocusScopeNode觉得最合适的节点。当然FocusScopeNode会根据使用[FocusScopeNode.setFirstFocus]设置为首先关注节点的节点的历史记录,判断出最合适的节点。
这一段我翻译得可能不太准确,所有附上官方解释吧!
if [focusPrevious] is true, then rather than losing all focus, the focus will be moved to the node that the [enclosingScope] thinks should have it, based on its history of nodes that were set as first focus on it using [FocusScopeNode.setFirstFocus]. -
addListener(VoidCallback listener)
FocusNode继承自ChangeNotifier,可以监听焦点的改变事件
// 创建 focusNode
FocusNode focusNode = new FocusNode();
// focusNode绑定输入框
TextField(focusNode: focusNode);
// 监听焦点变化
focusNode.addListener((){
print(focusNode.hasFocus);
});
获得焦点时focusNode.hasFocus值为true,失去焦点时为false。
四、自定义输入框样式
我们可以通过decoration属性来定义输入框样式:
TextField(
decoration: InputDecoration(
//在这里定义样式的属性
……
)
)
InputDecoration属性比较多,我们通过几个简单的例子来介绍它们。
1、下划线
下面是与下划线有关的属性
属性 | InputDecoration持有焦点 | InputDecoration显示errorText |
---|---|---|
errorBorder | NO | YES |
focusedBorder | YES | NO |
focusedErrorBorder | YES | YES |
属性 | InputDecoration可用 | InputDecoration显示errorText |
---|---|---|
disabledBorder | NO | NO |
enabledBorder | YES | NO |
例子:获取焦点时下划线为蓝色,失去焦点下划线为灰色
TextField(
keyboardType: TextInputType.phone,
maxLines: 1,
autofocus: false,
cursorColor: Colors.blue,
textInputAction: TextInputAction.next,
onSubmitted: (value) {
print("onSubmitted$value");
phoneFocusNode.nextFocus();
},
maxLength: 11,
maxLengthEnforced: true,
focusNode: phoneFocusNode,
// onChanged: (text) {
// print("phone=$text");
// },
controller: phoneController,
decoration: InputDecoration(
hintText: "请输入手机号码",
labelText: "手机号",
prefixIcon: Icon(Icons.phone),
// 未获得焦点下划线设为灰色
enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.grey),
),
//获得焦点下划线设为蓝色
focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.blue),
),
),
),
运行效果
2、其他属性
InputDecoration还有很多其他的属性,下图所示为比较常用的一些属性,更多属性请查阅文档: