UINavigationController指定VC自定义转场时保留侧滑返回的方案咨询
故障根因
当你实现了UINavigationControllerDelegate中的动画控制器代理方法后,系统会默认替换侧滑返回手势interactivePopGestureRecognizer的原有代理,你返回nil使用默认转场时,原有手势的判断逻辑没有正常触发,导致手势失效。
解决步骤
- 第一步:初始化导航代理时,先保存系统原有侧滑手势的代理对象,再将手势代理设置为当前导航代理类。
- 第二步:保持原有动画控制器代理的逻辑不变,仅目标VC场景返回自定义Animator,其余场景返回nil走系统默认转场。
- 第三步:实现交互转场代理方法,自定义转场无交互需求时直接返回nil。
- 第四步:实现
UIGestureRecognizerDelegate协议,非自定义转场场景将手势判断逻辑转发给之前保存的系统原有代理,保证默认手势行为正常。
代码示例
首先定义导航代理的存储属性:
// 持有导航控制器引用 weak var navigationController: UINavigationController? // 保存系统默认的侧滑手势代理 private var originalInteractivePopDelegate: UIGestureRecognizerDelegate?
初始化时配置手势:
// 设置导航代理时执行 func setup(for nav: UINavigationController) { navigationController = nav originalInteractivePopDelegate = nav.interactivePopGestureRecognizer?.delegate nav.interactivePopGestureRecognizer?.delegate = self nav.delegate = self }
原有动画控制器代理逻辑保持不变:
func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { // 仅自定义目标VC的push和pop转场 if operation == .push, toVC is TargetCustomViewController { return CustomPushAnimator() } else if operation == .pop, fromVC is TargetCustomViewController { return CustomPopAnimator() } // 其余场景走系统默认 return nil }
实现交互转场代理方法:
func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? { // 自定义转场需要支持交互侧滑时返回对应的交互控制器,无需求直接返回nil return nil }
实现手势代理方法转发逻辑:
extension NavigationDelegate: UIGestureRecognizerDelegate { func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool { guard gestureRecognizer == navigationController?.interactivePopGestureRecognizer, let nav = navigationController else { return true } // 根控制器禁止侧滑,和系统行为一致 if nav.viewControllers.count <= 1 { return false } // 自定义转场场景按需控制手势是否生效,此处示例为自定义转场不支持侧滑,你可以根据需求调整 if let topVC = nav.topViewController, topVC is TargetCustomViewController { return false } // 非自定义场景转发给系统原有代理 return originalInteractivePopDelegate?.gestureRecognizerShouldBegin?(gestureRecognizer) ?? true } func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool { guard gestureRecognizer == navigationController?.interactivePopGestureRecognizer else { return false } return originalInteractivePopDelegate?.gestureRecognizer?(gestureRecognizer, shouldRecognizeSimultaneouslyWith: otherGestureRecognizer) ?? false } }
补充说明
如果你的自定义转场需要支持交互侧滑,可以创建UIPercentDrivenInteractiveTransition实例,监听侧滑手势进度更新转场状态,手势结束时判断转场是完成还是取消即可。
内容的提问来源于stack exchange,提问作者Georg
相关产品推荐
相关产品推荐

