iOS 13/14 模态视图下滑关闭手势完成时机检测
精准识别iOS模态下滑手势完成关闭时机的可靠实现方案
首先明确核心问题:原有实现的回调时机滞后的本质,是误用了转场动画的完成回调——这类回调要等整个dismiss动画完全播放结束、视图从层级移除后才触发,自然无法匹配“用户刚完成手势判定、即将走完整个关闭流程”的时机。系统本身提供了专门适配交互转场的接口,不需要自行计算手势阈值就能实现精准检测。
推荐实现方案(系统原生支持,无版本适配风险)
核心是使用转场协调器提供的 notifyWhenInteractionChanges 方法替换原有的动画完成回调,这个接口会在用户手指离开屏幕、系统判定转场是完成还是取消的瞬间立刻触发,远早于动画全量结束的节点。
修正后的实现代码如下:
func presentationControllerWillDismiss(_ presentationController: UIPresentationController) { // 拿到当前模态视图对应的转场协调器,兼容非交互触发的dismiss(代码直接调用dismiss方法)场景 guard let transitionCoordinator = presentationController.presentedViewController.transitionCoordinator else { return } // 监听交互状态的变化,不需要等待动画播放完成 transitionCoordinator.notifyWhenInteractionChanges { context in if !context.isCancelled { // 触发时刻特征:用户已经完成拖拽松手,系统判定走完整dismiss流程,此时dismiss补间动画才刚启动 // 完全匹配需要的“即将走完整个关闭流程”的时机 print("检测到用户已完成关闭交互,即将执行完整dismiss流程") } else { // 触发时刻特征:用户已经松手,系统判定取消关闭,模态视图会执行回弹动画回到展示状态 print("检测到用户中途取消了关闭手势") } } }
方案可靠性说明
- 判定逻辑完全复用系统官方的手势识别规则,不需要自行计算滑动距离、滑动速度的判定阈值,不会出现和系统实际行为不一致的偏差
- 触发时机完全匹配需求:既不会像
presentationControllerWillDismiss那样刚按下拖拽就触发(此时用户还没确定要关闭),也不会像presentationControllerDidDismiss那样等视图完全消失才触发 - 全场景兼容:同时覆盖手势下滑触发的dismiss、代码主动调用dismiss方法触发的dismiss,不会出现场景漏触发的问题
- API在iOS13、iOS14版本上都是公开稳定接口,无私有API风险
不推荐的实现思路
不要通过自行监听模态视图上的下滑手势、计算滑动占比/速度来判断是否完成关闭:系统自带的下滑手势状态是私有维护的,自行实现的判定阈值很容易在不同iOS版本上和系统行为产生偏差,后续系统调整判定规则时维护成本很高。
内容的提问来源于stack exchange,提问作者Gizmodo
相关产品推荐
相关产品推荐

