Flutter:如何在不同类中通过超时移除Overlay?
问题原因与解决方案
问题根源
你每次调用Notify()都会生成一个全新的实例:
- 点击按钮时调用
Notify().show(context),创建的是实例A,这个实例里的_overlayEntry指向了插入的Overlay; - 超时后调用
Notify().dismiss(),创建的是实例B,这个实例的_overlayEntry是null,自然无法移除Overlay。
而Overlay内部点击时调用的是实例A自己的_overlayEntry?.remove(),所以能正常生效。
解决方案
方案1:在调用类中持有同一个Notify实例
修改Fd类,创建一个固定的Notify成员变量,确保show和dismiss调用的是同一个实例:
class Fd extends StatelessWidget{ late Timer rtime; int _start=4; int _dstart=4; // 持有同一个Notify实例 final Notify _notify = Notify(); Timer timeItOut() { const oneSec = const Duration(seconds: 1); rtime = Timer.periodic( oneSec, (Timer timer) { if (_start == 1) { _start = _dstart; rtime.cancel(); _notify.dismiss(); // 调用同一个实例的dismiss方法 } else { _start = _start - 1; print('still counting down $_start'); } } ); return rtime; } @override Widget build(BuildContext context){ return Scaffold( appBar: AppBar(title: const Text('Feeding the nation'),), body: Container( child:IconButton( icon: const Icon(Icons.food_bank), onPressed: (){ timeItOut(); _notify.show(context); // 调用同一个实例的show方法 }, ) ), ); } }
方案2:将Notify改为普通工具类(更合理)
因为Notify本质是管理Overlay的逻辑,不需要作为Widget存在,可以去掉StatelessWidget继承,改成普通类:
class Notify { OverlayEntry? _overlayEntry; void _insertOverlay(BuildContext context) { _overlayEntry = OverlayEntry(builder: (context) { return Positioned( width: MediaQuery.of(context).size.width, height: MediaQuery.of(context).size.height, top: 0, left: 0, child: Material( color: const Color(0xFF0E3311).withOpacity(0.2), child: GestureDetector( onTap: () => _overlayEntry?.remove(), child: const Icon(Icons.home, size: 100,), ) ), ); }); Overlay.of(context).insert(_overlayEntry!); } void show(BuildContext context){ _insertOverlay(context); } void dismiss(){ _overlayEntry?.remove(); // 移除后置空,避免重复调用导致异常 _overlayEntry = null; } }
搭配方案1的Fd类修改,就能正常实现超时移除Overlay的功能。
内容的提问来源于stack exchange,提问作者ubakasi
相关产品推荐
相关产品推荐

