导航到新页面时如何监听前一屏幕的Listener,实现长按弹窗拖拽选择功能?
问题根因
Flutter的手势事件默认优先分发到路由栈的顶层路由,你将弹窗放在独立的PageRoute中后,所有后续的指针事件都会被新路由拦截,即便给弹窗子组件加了IgnorePointer,事件也不会回传给下层路由的组件,因此前一个页面的Listener无法接收事件。
解决方案
可二选一实现:
方案1:改用Overlay承载弹窗(更推荐)
Overlay和当前页面属于同一路由,不会拦截当前页面的手势事件,完全符合peek选择的交互逻辑,实现示例如下:
// 长按按钮时触发 void _onLongPress(BuildContext context) { final overlay = Overlay.of(context); late OverlayEntry entry; entry = OverlayEntry( builder: (context) => OnMoveDialog(), ); overlay.insert(entry); // 可在当前页面的Listener的onPointerUp回调中调用 entry.remove() 销毁弹窗 } // 按钮组件修改为监听长按事件 ElevatedButton( onLongPress: () => _onLongPress(context), child: const Text('Show dialog'), )
当前页面的Listener可以正常接收所有onPointerMove、onPointerUp事件,只需在对应事件回调中处理选项选中、弹窗销毁逻辑即可。
方案2:在新路由中直接监听手势
如果你一定要用PageRoute承载弹窗,直接移除IgnorePointer,将所有手势监听逻辑移到新路由的顶层组件:
ElevatedButton( // 替换原有onPressed为onLongPress符合长按触发的需求 onLongPress: () { Navigator.of(context).push(PageRouteBuilder( pageBuilder: (context, animation, secondaryAnimation) { return Listener( onPointerMove: (event) { // 在这里处理选项选择逻辑 }, onPointerUp: (event) { Navigator.of(context).pop(); // 释放指针时关闭弹窗 }, child: OnMoveDialog(), ); }, opaque: false, )); }, child: const Text('Show dialog'), )
效果示意图
内容的提问来源于stack exchange,提问作者Khoa Le
相关产品推荐
相关产品推荐



