TextField
在 Flutter 开发中,TextField 是用于接收用户文本输入的核心组件,它功能强大且高度可定制。本文将全面介绍其核心概念、常用属性、事件监听、焦点管理以及自定义样式,帮助你快速掌握并灵活运用。
1. 核心概念与基本使用
TextField 遵循 Material Design 设计规范。最简单的用法是直接创建一个 TextField 实例,你会在屏幕上看到一个带下划线的输入框。
dart
TextField(
decoration: InputDecoration(
hintText: '请输入内容', // 提示文字
),
)
如果要完全移除装饰(包括下划线和为标签预留的空间),可以将 decoration 属性设置为 null 。
dart
TextField(
decoration:none,
)
Flutter 还提供了 TextFormField,它是对 TextField 的进一步封装,专门用于与 Form 表单集成,可以方便地实现表单验证和与其他表单字段的交互功能 -6。
2. 常用属性详解
TextField 提供了丰富的属性来控制其外观和行为。
2.1 控制器(controller)
controller 是 TextEditingController 类型的对象,它是与文本框交互的句柄。通过控制器可以获取或设置文本框的内容、监听文本变化、控制选中区域 等 -2。在实际开发中,如果你需要监听文本变化或动态修改文本框的值,建议显式地创建一个 TextEditingController 并管理其生命周期(在 StatefulWidget 的 dispose 方法中释放)-1。
scss
final TextEditingController _controller = TextEditingController();
@override
void initState() {
super.initState();
_controller.text = '初始值'; // 设置初始值
// 注意:设置完值后,可以通过调整 selection 属性来改变光标位置 [citation:2][citation:7]
_controller.selection = TextSelection.fromPosition(TextPosition(offset: _controller.text.length));
}
@override
Widget build(BuildContext context) {
return TextField(
controller: _controller,
);
}
@override
void dispose() {
_controller.dispose(); // 不要忘记释放
super.dispose();
}
2.2 装饰(decoration)
decoration 属性接受一个 InputDecoration 对象,用于控制输入框的外观,如标签、提示文本、图标、边框等。
| 属性 | 描述 | 示例 |
|---|---|---|
labelText |
输入框上方的标签文本。 | InputDecoration(labelText: '用户名') |
hintText |
输入框内的提示文本,用户输入后消失。 | InputDecoration(hintText: '请输入用户名') |
prefixIcon |
显示在输入框前部的图标。 | InputDecoration(prefixIcon: Icon(Icons.person)) |
suffixIcon |
显示在输入框后部的图标,常用于密码可见性切换。 | InputDecoration(suffixIcon: Icon(Icons.visibility)) |
border |
输入框的边框样式。 | InputDecoration(border: OutlineInputBorder()) |
filled / fillColor |
是否填充背景色及填充颜色。 | InputDecoration(filled: true, fillColor: Colors.grey[200]) |
2.3 键盘与输入类型
keyboardType: 设置弹出键盘的类型,如TextInputType.text(文本)、TextInputType.number(数字)、TextInputType.emailAddress(邮箱地址,会显示"@"和".")、TextInputType.phone(电话号码键盘)等 -2。textInputAction: 设置键盘右下角动作按钮的图标,如TextInputAction.done(完成)、TextInputAction.search(搜索)、TextInputAction.next(下一项)等,方便用户进行表单导航 -2。obscureText: 设置为true时,输入内容会被隐藏,用于密码输入框 -2。
2.4 输入格式与限制
maxLines: 设置输入框的最大行数。默认为 1,设置为null则表示无限多行 -2。minLines: 设置输入框的最小行数,需与maxLines配合使用 -8。maxLength: 设置允许输入的最大字符数。设置后,输入框右下角会显示字符计数器 -2。inputFormatters: 接受一个TextInputFormatter列表,用于限制输入格式,例如只允许输入数字或指定格式 -2。
less
TextField(
inputFormatters: [
FilteringTextInputFormatter.digitsOnly, // 只允许输入数字
],
)
enabled: 设置为false时,输入框将被禁用,不接收输入且显示禁用态样式 -2。
2.5 光标样式
可以通过 cursorWidth、cursorHeight、cursorRadius 和 cursorColor 属性来自定义光标的宽度、高度、圆角和颜色 -2。
less
TextField(
cursorColor: Colors.red, // 光标颜色
cursorWidth: 3.0, // 光标宽度
cursorRadius: Radius.circular(5.0), // 光标圆角
)
3. 事件监听与焦点管理
3.1 监听文本变化
有两种方式监听文本变化 -2:
onChanged回调:当用户每次改变输入框中的文本时都会触发,直接返回当前文本值。TextEditingController监听器 :通过controller.addListener(() {...})添加监听,可以获取更丰富的信息,如文本、选中区域等。
3.2 获取提交内容
onSubmitted: 当用户完成输入(如点击键盘上的"完成"或"搜索"按钮)时触发,返回当前文本值 -1。onEditingComplete: 也在用户完成编辑时调用,与onSubmitted行为略有不同。它默认会更新 controller 并使焦点失焦 -1。
3.3 焦点管理
focusNode: 通过FocusNode对象可以手动控制输入框的焦点,例如让某个输入框自动获得焦点、监听焦点变化、手动将焦点移动到下一个输入框或关闭键盘 。
dart
// 监听焦点变化
focusNode.addListener((){
print('焦点状态: ${focusNode.hasFocus}');
});
// 手动请求焦点
FocusScope.of(context).requestFocus(focusNode);
// 收起键盘 (取消所有焦点)
focusNode.unfocus();
autofocus: 设置为true时,页面加载后输入框会自动获得焦点 -2。
4. 样式自定义与综合示例
4.1 自定义边框
默认 TextField 是下划线样式,你可以通过 decoration 中的 border、enabledBorder、focusedBorder 等属性自定义不同状态下的边框样式 -2。
less
TextField(
decoration: InputDecoration(
labelText: '密码',
border: OutlineInputBorder(), // 使用圆形边框
enabledBorder: OutlineInputBorder( // 未获焦点时的边框
borderSide: BorderSide(color: Colors.grey, width: 1.0),
),
focusedBorder: OutlineInputBorder( // 获得焦点时的边框
borderSide: BorderSide(color: Colors.blue, width: 2.0),
),
),
obscureText: true,
)
4.2 综合示例:登录表单
以下是一个结合了上述知识点的简单登录表单示例。
dart
import 'package:flutter/material.dart';
void main(List<String> args) {
runApp(MainPage());
}
class MainPage extends StatefulWidget {
MainPage({Key? key}) : super(key: key);
@override
_MainPageState createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
TextEditingController _userNameEditController = TextEditingController();
TextEditingController _userPwdEditConroller = TextEditingController();
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text("登录"),
),
body: Container(
padding: EdgeInsets.all(10),
child: Column(
children: [
TextField(
cursorColor: Colors.red, // 光标颜色
cursorWidth: 3.0, // 光标宽度
cursorRadius: Radius.circular(5.0), // 光标圆角
controller: _userNameEditController,
onChanged: (value){
print("change"+value);
},
onSubmitted: (value){
print(value);
},
decoration: InputDecoration(
labelText: '用户名',
hintText: "请输入账号",
prefixIcon: Icon(Icons.person),
contentPadding: EdgeInsets.only(left: 10),
fillColor: const Color.fromARGB(255, 236, 236, 234),
filled: true, // 是否使用自定义颜色
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(25)
),
enabledBorder: OutlineInputBorder( // 未获焦点时的边框
borderSide: BorderSide(color: Colors.grey, width: 1.0),
),
focusedBorder: OutlineInputBorder( // 获得焦点时的边框
borderSide: BorderSide(color: Colors.blue, width: 2.0),
),
),
),
SizedBox(
height: 20,
),
TextField(
controller: _userPwdEditConroller,
obscureText: true, // 不显示实际内容
decoration: InputDecoration(
hintText: "请输入密码",
suffixIcon: Icon(Icons.visibility),
contentPadding: EdgeInsets.only(left: 10),
fillColor: const Color.fromARGB(255, 236, 236, 234),
filled: true,
border: OutlineInputBorder(
borderSide: BorderSide.none,
borderRadius: BorderRadius.circular(25)
)
),
),
SizedBox(
height: 20,
),
TextButton(onPressed: (){
print("${_userNameEditController.text}");
}, child: Text("登录"))
],
),
)
),
);
}
}