Flutter 输入组件全面指南
Flutter 提供了丰富的输入组件,用于构建用户交互界面。这些组件遵循 Material Design 规范,同时提供了强大的自定义能力。下面我将详细介绍 Flutter 中的主要输入组件及其用法。
核心输入组件
1. TextField - 基础文本输入框
dart
TextField(
decoration: InputDecoration(
labelText: '用户名',
hintText: '请输入您的用户名',
prefixIcon: Icon(Icons.person),
border: OutlineInputBorder(),
filled: true,
fillColor: Colors.grey[100],
),
keyboardType: TextInputType.text,
textInputAction: TextInputAction.next,
onChanged: (value) {
print('输入内容: $value');
},
onSubmitted: (value) {
print('提交内容: $value');
},
)
2. TextFormField - 表单文本输入框(带验证)
dart
TextFormField(
controller: _emailController,
decoration: InputDecoration(
labelText: '邮箱',
hintText: 'example@domain.com',
prefixIcon: Icon(Icons.email),
border: OutlineInputBorder(),
),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value == null || value.isEmpty) {
return '请输入邮箱地址';
}
if (!RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$').hasMatch(value)) {
return '邮箱格式不正确';
}
return null;
},
)
选择器组件
3. Checkbox - 复选框
dart
bool _isChecked = false;
Checkbox(
value: _isChecked,
onChanged: (bool? value) {
setState(() {
_isChecked = value!;
});
},
)
4. CheckboxListTile - 带标签的复选框
dart
bool _isChecked = false;
CheckboxListTile(
title: Text('同意用户协议'),
subtitle: Text('请仔细阅读用户协议'),
value: _isChecked,
onChanged: (bool? value) {
setState(() {
_isChecked = value!;
});
},
secondary: Icon(Icons.description),
)
5. Switch - 开关
dart
bool _isSwitched = false;
Switch(
value: _isSwitched,
onChanged: (bool value) {
setState(() {
_isSwitched = value;
});
},
)
6. Radio - 单选按钮
dart
enum Gender { male, female }
Gender? _selectedGender = Gender.male;
Column(
children: [
RadioListTile<Gender>(
title: Text('男性'),
value: Gender.male,
groupValue: _selectedGender,
onChanged: (Gender? value) {
setState(() {
_selectedGender = value;
});
},
),
RadioListTile<Gender>(
title: Text('女性'),
value: Gender.female,
groupValue: _selectedGender,
onChanged: (Gender? value) {
setState(() {
_selectedGender = value;
});
},
),
],
)
7. Slider - 滑块
dart
double _sliderValue = 50;
Slider(
value: _sliderValue,
min: 0,
max: 100,
divisions: 10,
label: _sliderValue.round().toString(),
onChanged: (double value) {
setState(() {
_sliderValue = value;
});
},
)
8. RangeSlider - 范围滑块
dart
RangeValues _currentRangeValues = RangeValues(20, 80);
RangeSlider(
values: _currentRangeValues,
min: 0,
max: 100,
divisions: 10,
labels: RangeLabels(
_currentRangeValues.start.round().toString(),
_currentRangeValues.end.round().toString(),
),
onChanged: (RangeValues values) {
setState(() {
_currentRangeValues = values;
});
},
)
9. DropdownButton - 下拉选择框
dart
String? _selectedItem = '选项1';
List<String> _items = ['选项1', '选项2', '选项3'];
DropdownButton<String>(
value: _selectedItem,
items: _items.map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (String? newValue) {
setState(() {
_selectedItem = newValue;
});
},
)
日期和时间选择器
10. showDatePicker - 日期选择器
dart
DateTime? _selectedDate;
ElevatedButton(
onPressed: () async {
final DateTime? picked = await showDatePicker(
context: context,
initialDate: DateTime.now(),
firstDate: DateTime(2000),
lastDate: DateTime(2100),
builder: (context, child) {
return Theme(
data: ThemeData.light().copyWith(
colorScheme: ColorScheme.light(
primary: Colors.blue,
onPrimary: Colors.white,
),
),
child: child!,
);
},
);
if (picked != null && picked != _selectedDate) {
setState(() {
_selectedDate = picked;
});
}
},
child: Text('选择日期'),
)
11. showTimePicker - 时间选择器
dart
TimeOfDay? _selectedTime;
ElevatedButton(
onPressed: () async {
final TimeOfDay? picked = await showTimePicker(
context: context,
initialTime: TimeOfDay.now(),
builder: (context, child) {
return Theme(
data: ThemeData.light().copyWith(
colorScheme: ColorScheme.light(
primary: Colors.blue,
onPrimary: Colors.white,
),
),
child: child!,
);
},
);
if (picked != null && picked != _selectedTime) {
setState(() {
_selectedTime = picked;
});
}
},
child: Text('选择时间'),
)
表单处理
12. Form 和 GlobalKey
dart
final _formKey = GlobalKey<FormState>();
TextEditingController _nameController = TextEditingController();
TextEditingController _emailController = TextEditingController();
TextEditingController _passwordController = TextEditingController();
Form(
key: _formKey,
child: Column(
children: [
TextFormField(
controller: _nameController,
decoration: InputDecoration(labelText: '姓名'),
validator: (value) {
if (value == null || value.isEmpty) {
return '请输入姓名';
}
return null;
},
),
TextFormField(
controller: _emailController,
decoration: InputDecoration(labelText: '邮箱'),
keyboardType: TextInputType.emailAddress,
validator: (value) {
if (value == null || value.isEmpty) {
return '请输入邮箱';
}
if (!value.contains('@')) {
return '邮箱格式不正确';
}
return null;
},
),
TextFormField(
controller: _passwordController,
decoration: InputDecoration(labelText: '密码'),
obscureText: true,
validator: (value) {
if (value == null || value.length < 6) {
return '密码长度至少6位';
}
return null;
},
),
ElevatedButton(
onPressed: () {
if (_formKey.currentState!.validate()) {
// 表单验证通过
print('姓名: ${_nameController.text}');
print('邮箱: ${_emailController.text}');
print('密码: ${_passwordController.text}');
}
},
child: Text('提交'),
),
],
),
)
高级输入组件
13. Autocomplete - 自动完成
dart
final List<String> _options = [
'Apple',
'Banana',
'Cherry',
'Date',
'Fig',
'Grape',
'Lemon',
'Mango',
'Orange',
'Peach',
'Pear',
'Pineapple',
'Strawberry',
];
Autocomplete<String>(
optionsBuilder: (TextEditingValue textEditingValue) {
if (textEditingValue.text == '') {
return const Iterable<String>.empty();
}
return _options.where((String option) {
return option.toLowerCase().contains(textEditingValue.text.toLowerCase());
});
},
onSelected: (String selection) {
print('选择了: $selection');
},
)
14. SearchBar - 搜索框
dart
SearchBar(
hintText: '搜索...',
leading: Icon(Icons.search),
trailing: [
IconButton(
icon: Icon(Icons.filter_list),
onPressed: () {
print('打开筛选器');
},
),
],
onChanged: (value) {
print('搜索内容: $value');
},
onSubmitted: (value) {
print('提交搜索: $value');
},
)
自定义输入组件
15. 自定义表单字段
dart
class CustomInputField extends StatelessWidget {
final String label;
final IconData? icon;
final bool obscureText;
final TextEditingController? controller;
final String? Function(String?)? validator;
const CustomInputField({
required this.label,
this.icon,
this.obscureText = false,
this.controller,
this.validator,
});
@override
Widget build(BuildContext context) {
return TextFormField(
controller: controller,
obscureText: obscureText,
decoration: InputDecoration(
labelText: label,
prefixIcon: icon != null ? Icon(icon) : null,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
),
filled: true,
fillColor: Colors.grey[100],
),
validator: validator,
);
}
}
// 使用示例
CustomInputField(
label: '密码',
icon: Icons.lock,
obscureText: true,
validator: (value) {
if (value == null || value.isEmpty) {
return '密码不能为空';
}
return null;
},
)
最佳实践
- 表单验证:始终验证用户输入,提供清晰的错误信息
- 键盘类型 :根据输入内容选择合适的键盘类型(
keyboardType) - 无障碍性:确保所有输入组件都有适当的标签和语义
- 状态管理:使用控制器管理文本输入状态
- 输入格式 :使用
inputFormatters限制输入格式 - 错误处理:优雅地处理验证错误
- 焦点管理 :使用
FocusNode管理输入焦点
dart
// 焦点管理示例
FocusNode _emailFocus = FocusNode();
FocusNode _passwordFocus = FocusNode();
TextFormField(
focusNode: _emailFocus,
decoration: InputDecoration(labelText: '邮箱'),
textInputAction: TextInputAction.next,
onFieldSubmitted: (value) {
FocusScope.of(context).requestFocus(_passwordFocus);
},
)
总结
Flutter 提供了丰富的输入组件,从基本的文本输入到复杂的日期选择器,满足各种用户输入需求。关键组件包括:
- TextField/TextFormField:用于文本输入
- 选择器:Checkbox, Switch, Radio, Slider, DropdownButton
- 日期/时间选择器:showDatePicker, showTimePicker
- 表单处理:Form, GlobalKey, 验证逻辑
- 高级组件:Autocomplete, SearchBar
通过组合这些组件并遵循最佳实践,您可以创建直观、高效且用户友好的输入界面。