Flutter:TextEditingController已释放后被使用报错(Dismissible删除场景)
问题原因
- 你的列表组件未给每个自定义Widget设置唯一Key,Flutter更新列表时会复用现有Widget实例。删除非最后一项后,原本在被删除项后的Widget会被“前移”复用,而被删除Widget的
TextEditingController已在其dispose()中释放,复用后的Widget仍持有这个已释放的控制器引用,点击TextFormField就会触发错误。 - 删除最后一项时没有后续Widget需要复用,因此不会出现问题。
解决方案
给每个自定义Widget绑定唯一Key
基于数据的唯一标识(比如食材卡片的id)给列表项设置Key,确保Flutter不会错误复用Widget实例:ListView.builder( itemCount: ingredientList.length, itemBuilder: (context, index) { final ingredient = ingredientList[index]; return Dismissible( key: ValueKey(ingredient.id), child: CustomIngredientWidget( key: ValueKey(ingredient.id), ingredient: ingredient, ), onDismissed: (direction) { Provider.of<IngredientProvider>(context, listen: false) .removeIngredientCard(ingredient.id); }, ); }, )保证控制器与Widget生命周期绑定正确
自定义Widget需在dispose()中释放控制器,结合Key的正确使用,确保每个Widget实例的控制器不会被错误复用:class CustomIngredientWidget extends StatefulWidget { final Ingredient ingredient; const CustomIngredientWidget({super.key, required this.ingredient}); @override State<CustomIngredientWidget> createState() => _CustomIngredientWidgetState(); } class _CustomIngredientWidgetState extends State<CustomIngredientWidget> { late TextEditingController _controller; @override void initState() { super.initState(); _controller = TextEditingController(text: widget.ingredient.text); } @override void dispose() { _controller.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return TextFormField(controller: _controller); } }不要用列表索引作为标识
避免将列表index作为Key,删除项后索引会变化,仍可能引发复用问题,必须使用数据本身的唯一标识(如id、UUID等)。
内容的提问来源于stack exchange,提问作者Sebb
相关产品推荐
相关产品推荐

