Flutter Web中InkWell的onHover事件触发AnimationController已销毁异常如何解决
错误原因
报错的核心诱因是事件冒泡+组件提前销毁:
IconButton本身自带悬停交互动画,当鼠标从外层InkWell区域移动到内部的IconButton上时,会先触发父级InkWell的onHover(isHoverIn: false)事件,此时你执行setState直接把IconButton从组件树中移除。- 但
IconButton被移除时,它内部管理悬停动效的AnimationController已经触发了reverse()回调,回调执行时控制器已经随着IconButton的销毁被dispose了,所以抛出断言异常。
你打印的三次日志也刚好对应这个完整流程:
- 鼠标进入InkWell → 触发
isHoverIn: true,显示按钮 - 鼠标移到IconButton上 → 触发父InkWell的
isHoverIn: false,准备销毁按钮 - 按钮销毁瞬间鼠标还在原InkWell区域 → 再次触发
isHoverIn: true,重新渲染按钮
解决方案
方案1:隐藏而非销毁IconButton(最简便,推荐)
不要用条件判断直接移除IconButton,改用Opacity+IgnorePointer控制显隐,组件不会被销毁,也就不会出现动画控制器被提前释放的问题。IgnorePointer 用来保证按钮隐藏时不会响应点击事件,避免误触。
代码修改如下:
child: Stack( children: [ // 原有装饰背景保留 Positioned.fill( child: Container( height: boxSize, width: boxSize, decoration: BoxDecoration( image: DecorationImage( image: widget.imageData.image!.image, fit: BoxFit.cover, ), border: Border.all( color: Colors.grey, width: 5, ), borderRadius: BorderRadius.circular(12), ), ), ), // IconButton常驻,仅控制显隐 Align( alignment: Alignment.topRight, child: IgnorePointer( ignoring: !isCancelButtonVisible, child: Opacity( opacity: isCancelButtonVisible ? 1 : 0, child: IconButton( iconSize: 20, icon: const Icon(Icons.cancel), tooltip: 'rimuovi', onPressed: () => widget.onRemove(widget.position), ), ), ), ) ], ),
方案2:阻止IconButton的悬停事件冒泡
给IconButton外层套MouseRegion,手动拦截hover事件,避免触发父级InkWell的离开回调:
Align( alignment: Alignment.topRight, child: MouseRegion( onHover: (_) {}, child: IconButton( iconSize: 20, icon: const Icon(Icons.cancel), tooltip: 'rimuovi', onPressed: () => widget.onRemove(widget.position), ), ), )
方案3:延迟状态更新(兜底方案)
如果不想改布局结构,可以给状态更新加个极短的延迟,等IconButton的动画回调执行完再销毁组件,注意要加mounted判断避免页面销毁后触发异常:
onHover: (bool isHoverIn) { print("isHoverIN: $isHoverIn iscancel: $isCancelButtonVisible"); if (isHoverIn != isCancelButtonVisible) { Future.delayed(const Duration(milliseconds: 50), () { if (mounted) { setState(() { isCancelButtonVisible = isHoverIn; }); } }); } },
内容的提问来源于stack exchange,提问作者blob
相关产品推荐
相关产品推荐

