Flutter实现iPhone Notes式清单:交互功能及状态管理方案咨询
实现类似iPhone Notes清单功能的解决方案
核心思路
不需要引入GetX这类状态管理库,通过Flutter原生状态提升就能实现需求。核心是让父组件统一管理所有清单项的状态(文本、勾选状态、输入控制器),子组件仅负责UI渲染和事件传递,实现增删交互。
步骤1:定义数据类与父组件状态管理
在父组件中维护子任务列表、对应的输入控制器,同时实现增删、状态更新的方法:
class TaskForm extends StatefulWidget { const TaskForm({Key? key}) : super(key: key); @override State<TaskForm> createState() => _TaskFormState(); } class _TaskFormState extends State<TaskForm> { // 存储子任务数据(文本+勾选状态) List<SubTask> _subTasks = []; // 存储每个输入框的控制器 List<TextEditingController> _controllers = []; @override void initState() { super.initState(); // 初始化第一个空清单项 _addSubTask(); } // 新增清单项 void _addSubTask({String initialText = ''}) { final controller = TextEditingController(text: initialText); _subTasks.add(SubTask(text: initialText, isChecked: false)); _controllers.add(controller); setState(() {}); // 新增后自动聚焦到新输入框 WidgetsBinding.instance.addPostFrameCallback((_) { FocusScope.of(context).requestFocus(FocusNode()); }); } // 删除清单项(至少保留一个空项) void _deleteSubTask(int index) { if (_subTasks.length > 1) { _controllers[index].dispose(); _controllers.removeAt(index); _subTasks.removeAt(index); setState(() {}); // 删除后聚焦到前一个输入框 if (index > 0) { FocusScope.of(context).requestFocus(FocusNode()); } } } // 更新勾选状态 void _onCheckboxChanged(int index, bool value) { setState(() { _subTasks[index].isChecked = value; }); } // 更新输入文本 void _onTextChanged(int index, String text) { setState(() { _subTasks[index].text = text; }); } @override void dispose() { // 销毁所有控制器,避免内存泄漏 for (var controller in _controllers) { controller.dispose(); } super.dispose(); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: const Text('清单')), body: ListView.builder( itemCount: _subTasks.length, itemBuilder: (context, index) { return SubTaskItem( controller: _controllers[index], isChecked: _subTasks[index].isChecked, onCheckboxChanged: (value) => _onCheckboxChanged(index, value), onDelete: () => _deleteSubTask(index), onEnter: () => _addSubTask(), onTextChanged: (text) => _onTextChanged(index, text), ); }, ), ); } } // 子任务数据模型 class SubTask { String text; bool isChecked; SubTask({required this.text, required this.isChecked}); }
步骤2:重构子组件(SubTaskItem)
将SubTaskItem改为无状态组件,接收父组件传递的状态和回调函数,处理键盘交互:
class SubTaskItem extends StatelessWidget { final TextEditingController controller; final bool isChecked; final ValueChanged<bool> onCheckboxChanged; final VoidCallback onDelete; final VoidCallback onEnter; final ValueChanged<String> onTextChanged; const SubTaskItem({ Key? key, required this.controller, required this.isChecked, required this.onCheckboxChanged, required this.onDelete, required this.onEnter, required this.onTextChanged, }) : super(key: key); @override Widget build(BuildContext context) { return CheckboxListTile( value: isChecked, onChanged: onCheckboxChanged, title: TextFormField( controller: controller, style: const TextStyle(fontSize: 14.0), onChanged: onTextChanged, // 处理键盘事件:退格删除、回车新增 onKeyEvent: (node, event) { // 文本为空时按退格,触发删除 if (event.logicalKey == LogicalKeyboardKey.backspace && controller.text.isEmpty) { onDelete(); return KeyEventResult.handled; } // 按回车触发新增 if (event.logicalKey == LogicalKeyboardKey.enter) { onEnter(); return KeyEventResult.handled; } return KeyEventResult.ignored; }, decoration: const InputDecoration( border: InputBorder.none, hintText: '输入子任务', ), ), controlAffinity: ListTileControlAffinity.leading, activeColor: Colors.green, ); } }
关键交互说明
- 退格删除:监听退格键,当输入框文本为空时,调用父组件的
_deleteSubTask方法移除当前项。 - 回车新增:监听回车键,调用父组件的
_addSubTask方法添加新的空项,并自动聚焦到新输入框。 - 焦点管理:新增/删除后自动调整焦点位置,提升用户操作流畅度。
是否需要GetX?
不需要。这个功能逻辑简单,通过Flutter原生的状态提升+setState就能完全实现,代码更轻量且无额外依赖。如果你的项目已经在使用GetX,也可以用GetX来管理列表状态,但对于该需求来说,原生方案是更简便的选择。
内容的提问来源于stack exchange,提问作者Soveyyy
相关产品推荐
相关产品推荐

