Flutter中如何触发操作时移除StatefulWidget内指定Row实现动态表单
Flutter动态表单增删行实现方案
核心问题说明
你原有代码存在两个核心问题导致删除功能无法正常生效:
- 每次
build方法执行时都会重新创建两个Row并加入Rows数组,即使之前删除了某行,页面下次重绘又会恢复成两行 - 直接将Widget作为状态存储不符合Flutter设计规范,应该优先存储表单数据源,再通过数据源动态构建Widget
实现逻辑
我们通过维护表单数据源的方式实现动态增删:
- 定义表单项的数据结构,存储每个输入行的标签、文本编辑控制器(用于获取用户输入内容)
- State中仅维护表单项数据数组,不直接存储Row组件
build方法遍历数据源数组,动态生成对应的Row组件- 删除按钮点击时,通过索引删除数据源中对应项,调用
setState触发重绘即可完成行删除 - 若需新增行,只需往数据源数组中添加新的表单项,调用
setState即可
完整可运行代码
import 'package:flutter/material.dart'; // 定义表单项数据模型 class FormItem { final String label; final TextEditingController controller; final EdgeInsets? margin; FormItem({ required this.label, required this.controller, this.margin, }); } class EditForm2 extends StatefulWidget { @override _EditForm2State createState() => _EditForm2State(); } class _EditForm2State extends State<EditForm2> { // 维护表单项数据源,而不是Row数组 late List<FormItem> _formItems; @override void initState() { super.initState(); // 初始化两个默认表单项 _formItems = [ FormItem( label: 'Link', controller: TextEditingController(text: 'test link'), margin: const EdgeInsets.symmetric(horizontal: 30), ), FormItem( label: 'Geo', controller: TextEditingController(text: '0.50;0.44'), margin: const EdgeInsets.only(left: 30, right: 30, bottom: 50), ), ]; } @override void dispose() { // 销毁所有控制器,防止内存泄漏 for (var item in _formItems) { item.controller.dispose(); } super.dispose(); } // 删除行方法 void _deleteRow(int index) { setState(() { // 先销毁对应控制器 _formItems[index].controller.dispose(); // 从数据源中移除对应项 _formItems.removeAt(index); }); } @override Widget build(BuildContext context) { // 动态构建所有Row List<Row> rows = _formItems.asMap().entries.map((entry) { int index = entry.key; FormItem item = entry.value; return Row( children: [ Expanded( flex: 3, child: Container( margin: item.margin, child: Text( item.label, style: const TextStyle( color: Colors.black54, fontSize: 20.0, letterSpacing: 0, fontWeight: FontWeight.normal, ), ), ), ), Expanded( flex: 6, child: Container( margin: item.margin, child: TextFormField( controller: item.controller, ), ), ), Container( margin: const EdgeInsets.only(right: 30.0), child: Ink( decoration: const ShapeDecoration( color: Colors.red, shape: CircleBorder(), ), child: IconButton( icon: const Icon( Icons.remove, color: Colors.white, ), // 点击调用删除方法,传入当前行索引 onPressed: () => _deleteRow(index), ), ), ), ], ); }).toList(); return Column(children: rows); } }
新增行扩展
如果需要实现新增行功能,只需添加如下方法,在页面新增按钮中调用即可:
void _addNewRow() { setState(() { _formItems.add(FormItem( label: '新项${_formItems.length + 1}', controller: TextEditingController(text: ''), margin: const EdgeInsets.symmetric(horizontal: 30), )); }); }
内容的提问来源于stack exchange,提问作者user3688227
相关产品推荐
相关产品推荐

