Flutter中WillPopScope与Overlay Widget不兼容问题求助
问题原因及解决方案
问题原因
Flutter的返回键事件由当前页面的Navigator路由栈负责处理,而你通过OverlayEntry添加的组件是挂载在Overlay独立层级上的,不属于Navigator的路由栈结构,所以包裹在OverlayEntry里的WillPopScope根本接收不到返回事件回调,自然不会生效。
解决方案
方案一:用ScopedWillPopCallback注册返回回调
直接给当前页面的ModalRoute添加返回事件回调,这样就能捕获返回键操作,进而处理Overlay的移除逻辑。修改后的代码如下:
bool isOverlayOnScreen = false; late OverlayEntry? globaOverlayEntry; VoidCallback? _popCallback; showOverlayWidget({required BuildContext context,required Widget widgetToDisplay})async{ OverlayState? overlayState = Overlay.of(context); globaOverlayEntry = OverlayEntry( maintainState: true, builder: (context) => widgetToDisplay, ); isOverlayOnScreen = true; overlayState.insert(globaOverlayEntry!); // 注册返回回调 _popCallback = () async { if (isOverlayOnScreen) { print("Print Will of Stack widget called----2"); removeGlobalOverlay(); return false; // 返回false阻止页面默认返回行为,仅关闭Overlay } return true; }; ModalRoute.of(context)?.addScopedWillPopCallback(_popCallback!); } void removeGlobalOverlay() { // 先移除回调,避免内存泄漏 if (_popCallback != null && globaOverlayEntry != null) { ModalRoute.of(globaOverlayEntry!.context)?.removeScopedWillPopCallback(_popCallback!); _popCallback = null; } globaOverlayEntry?.remove(); globaOverlayEntry?.dispose(); isOverlayOnScreen = false; globaOverlayEntry = null; } void showWidgetScreen(BuildContext context,Widget widgetToDisplay) { showDialog( context: context, builder: (BuildContext context) { return widgetToDisplay; }, ); }
注意事项
- 移除Overlay时必须同步移除注册的回调,防止内存泄漏;
- 代码中
return false是为了只关闭Overlay而不触发页面本身的返回,如果需要关闭Overlay同时返回上一页,改成return true即可。
内容的提问来源于stack exchange,提问作者Ashish Tandon
相关产品推荐
相关产品推荐

