输入组件详解
输入组件是与用户交互的核心,包括按钮、文本输入、选择器等。本教程将详细介绍 Flutter 中最常用的输入组件。
重要提示:Flutter 3.27+ 增强了 Material 3 组件的功能,提供了更多自定义选项和更好的用户体验。
1. TextField 文本输入框
TextField 是最常用的文本输入组件,支持单行和多行输入、自动验证、格式化等功能。
核心属性
| 属性 | 类型 | 说明 |
|---|---|---|
| controller | TextEditingController | 控制器,用于访问和修改文本 |
| decoration | InputDecoration | 装饰,设置外观和标签 |
| keyboardType | TextInputType | 键盘类型 |
| textInputAction | TextInputAction | 键盘动作按钮 |
| obscureText | bool | 是否隐藏文本(密码输入) |
| maxLength | int | 最大长度 |
| maxLines | int | 最大行数 |
| enabled | bool | 是否启用 |
| readOnly | bool | 是否只读 |
使用示例
// 基本 TextField
TextField(
decoration: const InputDecoration(
labelText: '用户名',
hintText: '请输入用户名',
border: OutlineInputBorder(),
),
)
// 带控制器的 TextField
final TextEditingController _controller = TextEditingController();
TextField(
controller: _controller,
decoration: const InputDecoration(
labelText: '用户名',
prefixIcon: Icon(Icons.person),
suffixIcon: Icon(Icons.check),
),
onChanged: (value) {
print('输入: $value');
},
onSubmitted: (value) {
print('提交: $value');
},
)
// 密码输入框
TextField(
obscureText: true,
decoration: const InputDecoration(
labelText: '密码',
hintText: '请输入密码',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.lock),
),
)
// 多行文本输入
TextField(
maxLines: 5,
decoration: const InputDecoration(
labelText: '简介',
hintText: '请输入简介',
border: OutlineInputBorder(),
),
)
// 数字输入
TextField(
keyboardType: TextInputType.number,
decoration: const InputDecoration(
labelText: '年龄',
border: OutlineInputBorder(),
),
)
// 带验证的 TextField
TextField(
controller: _emailController,
keyboardType: TextInputType.emailAddress,
decoration: InputDecoration(
labelText: '邮箱',
hintText: '请输入邮箱',
border: const OutlineInputBorder(),
errorText: _emailError.isEmpty ? null : _emailError,
),
onChanged: (value) {
setState(() {
_emailError = _validateEmail(value) ? '' : '邮箱格式不正确';
});
},
)
// 带前缀和后缀的 TextField
TextField(
decoration: InputDecoration(
labelText: '金额',
prefixText: '¥ ',
suffixText: '元',
border: const OutlineInputBorder(),
),
)
技巧:使用 TextEditingController 可以更灵活地控制文本,包括设置初始值、获取文本、选择文本等。
2. TextFormField 表单输入框
TextFormField 是 TextField 的封装,提供了表单验证功能,适合用于表单场景。
使用示例
// 基本 TextFormField
TextFormField(
decoration: const InputDecoration(
labelText: '邮箱',
border: OutlineInputBorder(),
),
validator: (value) {
if (value == null || value.isEmpty) {
return '请输入邮箱';
}
if (!value.contains('@')) {
return '邮箱格式不正确';
}
return null;
},
)
// 完整的登录表单
Form(
key: _formKey,
child: Column(
children: [
TextFormField(
controller: _usernameController,
decoration: const InputDecoration(
labelText: '用户名',
prefixIcon: Icon(Icons.person),
border: OutlineInputBorder(),
),
validator: (value) {
if (value == null || value.isEmpty) {
return '请输入用户名';
}
if (value.length < 3) {
return '用户名至少3个字符';
}
return null;
},
),
const SizedBox(height: 16),
TextFormField(
controller: _passwordController,
obscureText: _obscurePassword,
decoration: InputDecoration(
labelText: '密码',
prefixIcon: const Icon(Icons.lock),
suffixIcon: IconButton(
icon: Icon(
_obscurePassword ? Icons.visibility : Icons.visibility_off,
),
onPressed: () {
setState(() {
_obscurePassword = !_obscurePassword;
});
},
),
border: const OutlineInputBorder(),
),
validator: (value) {
if (value == null || value.isEmpty) {
return '请输入密码';
}
if (value.length < 6) {
return '密码至少6个字符';
}
return null;
},
),
const SizedBox(height: 24),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
// 表单验证通过
_login();
}
},
child: const Text('登录'),
),
],
),
)
3. ElevatedButton 凸起按钮
ElevatedButton 是 Material Design 风格的凸起按钮,适合用于主要操作。
使用示例
// 基本 ElevatedButton
ElevatedButton(
onPressed: () {
print('按钮被点击');
},
child: const Text('点击我'),
)
// 带图标的按钮
ElevatedButton.icon(
onPressed: () {},
icon: const Icon(Icons.send),
label: const Text('发送'),
)
// 自定义样式
ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
backgroundColor: Colors.blue,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(
horizontal: 24,
vertical: 12,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
child: const Text('自定义按钮'),
)
// 禁用状态
ElevatedButton(
onPressed: null,
child: const Text('禁用按钮'),
)
// 全宽按钮
SizedBox(
width: double.infinity,
child: ElevatedButton(
onPressed: () {},
style: ElevatedButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16),
),
child: const Text('全宽按钮'),
),
)
4. TextButton 文本按钮
TextButton 是扁平的文本按钮,适合用于次要操作或导航。
使用示例
// 基本 TextButton
TextButton(
onPressed: () {
print('文本按钮被点击');
},
child: const Text('取消'),
)
// 带图标的文本按钮
TextButton.icon(
onPressed: () {},
icon: const Icon(Icons.cancel),
label: const Text('取消'),
)
// 自定义样式
TextButton(
onPressed: () {},
style: TextButton.styleFrom(
foregroundColor: Colors.red,
textStyle: const TextStyle(fontSize: 16),
),
child: const Text('删除'),
)
5. OutlinedButton 轮廓按钮
OutlinedButton 是带边框的按钮,介于 ElevatedButton 和 TextButton 之间。
使用示例
// 基本 OutlinedButton
OutlinedButton(
onPressed: () {},
child: const Text('轮廓按钮'),
)
// 带图标的轮廓按钮
OutlinedButton.icon(
onPressed: () {},
icon: const Icon(Icons.share),
label: const Text('分享'),
)
// 自定义样式
OutlinedButton(
onPressed: () {},
style: OutlinedButton.styleFrom(
foregroundColor: Colors.blue,
side: const BorderSide(
color: Colors.blue,
width: 2,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
child: const Text('自定义轮廓按钮'),
)
6. IconButton 图标按钮
IconButton 是只包含图标的按钮,适合用于工具栏或图标操作。
使用示例
// 基本 IconButton
IconButton(
onPressed: () {
print('图标按钮被点击');
},
icon: const Icon(Icons.favorite),
iconSize: 32,
color: Colors.red,
)
// 带工具提示的图标按钮
IconButton(
onPressed: () {},
icon: const Icon(Icons.delete),
tooltip: '删除',
color: Colors.red,
)
// 不同大小的图标按钮
Row(
children: [
IconButton(
onPressed: () {},
icon: const Icon(Icons.star),
iconSize: 24,
),
IconButton(
onPressed: () {},
icon: const Icon(Icons.star),
iconSize: 32,
),
IconButton(
onPressed: () {},
icon: const Icon(Icons.star),
iconSize: 48,
),
],
)
// 浮动操作按钮(FAB)
FloatingActionButton(
onPressed: () {},
child: const Icon(Icons.add),
)
// 大号 FAB
FloatingActionButton.extended(
onPressed: () {},
icon: const Icon(Icons.camera_alt),
label: const Text('拍照'),
)
7. Checkbox 复选框
Checkbox 用于选择多个选项的状态。
使用示例
// 基本 Checkbox
bool _isChecked = false;
Checkbox(
value: _isChecked,
onChanged: (bool? value) {
setState(() {
_isChecked = value ?? false;
});
},
)
// 带标签的复选框
CheckboxListTile(
title: const Text('我同意服务条款'),
subtitle: const Text('请仔细阅读条款内容'),
value: _agreeToTerms,
onChanged: (bool? value) {
setState(() {
_agreeToTerms = value ?? false;
});
},
controlAffinity: ListTileControlAffinity.leading,
)
// 三态复选框
TriStateCheckbox(
value: _tristateValue,
onChanged: (bool? value) {
setState(() {
_tristateValue = value;
});
},
)
8. Radio 单选按钮
Radio 用于从多个选项中选择一个。
使用示例
// 基本 Radio
enum Gender { male, female }
Gender? _gender = Gender.male;
Radio(
value: Gender.male,
groupValue: _gender,
onChanged: (Gender? value) {
setState(() {
_gender = value;
});
},
)
// 带标签的单选按钮
RadioListTile(
title: const Text('男'),
subtitle: const Text('选择男性'),
value: Gender.male,
groupValue: _gender,
onChanged: (Gender? value) {
setState(() {
_gender = value;
});
},
)
9. Switch 开关
Switch 用于切换开/关状态。
使用示例
// 基本 Switch
bool _isSwitched = false;
Switch(
value: _isSwitched,
onChanged: (bool value) {
setState(() {
_isSwitched = value;
});
},
)
// 带标签的开关
SwitchListTile(
title: const Text('通知'),
subtitle: const Text('接收推送通知'),
value: _notificationsEnabled,
onChanged: (bool value) {
setState(() {
_notificationsEnabled = value;
});
},
)
// 自定义颜色
Switch(
value: _isSwitched,
onChanged: (bool value) {
setState(() {
_isSwitched = value;
});
},
activeColor: Colors.green,
activeTrackColor: Colors.green.withOpacity(0.5),
)
10. Slider 滑块
Slider 用于选择一个范围内的数值。
使用示例
// 基本 Slider
double _sliderValue = 50.0;
Slider(
value: _sliderValue,
min: 0,
max: 100,
divisions: 10,
label: _sliderValue.round().toString(),
onChanged: (double value) {
setState(() {
_sliderValue = value;
});
},
)
// 带图标的滑块
SliderTheme(
data: SliderTheme.of(context).copyWith(
activeTrackColor: Colors.red,
inactiveTrackColor: Colors.red.withOpacity(0.3),
thumbColor: Colors.red,
overlayColor: Colors.red.withOpacity(0.2),
),
child: Slider(
value: _sliderValue,
min: 0,
max: 100,
onChanged: (double value) {
setState(() {
_sliderValue = value;
});
},
),
)
11. Dropdown 下拉选择
DropdownButton 用于从下拉列表中选择一个选项。
使用示例
// 基本 DropdownButton
String? _selectedItem;
DropdownButton(
hint: const Text('请选择'),
value: _selectedItem,
items: const [
DropdownMenuItem(
value: 'Option 1',
child: Text('选项 1'),
),
DropdownMenuItem(
value: 'Option 2',
child: Text('选项 2'),
),
DropdownMenuItem(
value: 'Option 3',
child: Text('选项 3'),
),
],
onChanged: (String? value) {
setState(() {
_selectedItem = value;
});
},
)
// 带图标的下拉选择
DropdownButtonFormField(
decoration: const InputDecoration(
labelText: '城市',
border: OutlineInputBorder(),
prefixIcon: Icon(Icons.location_city),
),
value: _selectedCity,
items: ['北京', '上海', '广州', '深圳'].map((String city) {
return DropdownMenuItem(
value: city,
child: Text(city),
);
}).toList(),
onChanged: (String? value) {
setState(() {
_selectedCity = value;
});
},
)
输入组件最佳实践
- 为所有输入组件添加清晰的标签和提示文本
- 使用 TextEditingController 管理文本状态
- 为密码字段添加显示/隐藏切换功能
- 使用 Form 和 TextFormField 进行表单验证
- 根据操作重要性选择合适的按钮类型
- 为按钮添加合适的尺寸和间距
- 使用 Material Design 3 的新特性提升用户体验
- 为所有交互组件提供视觉反馈
提示:使用 Flutter 3.27+ 的 FormField 可以更灵活地实现自定义表单验证。
下一步:掌握输入组件后,继续学习列表组件和数据展示。