You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义UIViewController转场无法交互触发问题排查

问题分析与解决方案

这问题我之前也踩过一模一样的坑!核心原因主要有两个,咱们一步步拆解清楚:

1. 交互控制器的生命周期与转场代理时机不匹配

你在手势的.began阶段才创建interactionController,但此时调用popViewController(animated: true)后,导航控制器会立刻询问它的转场代理要交互控制器。如果你的interactionController是方法内的局部变量,或者代理方法无法访问到这个实例,导航控制器就会认为没有交互转场,直接执行默认的完整动画。

关键提醒:interactionController必须定义为当前ViewController的实例属性,不能是手势方法里的局部变量!否则转场代理根本拿不到这个对象,自然没法关联交互逻辑。

2. 转场代理方法未正确实现

你需要确保导航控制器的代理(通常就是当前的ViewController)实现了UINavigationControllerDelegate的两个核心方法:一个返回自定义动画控制器,另一个返回你的交互控制器,这样导航控制器才知道要用交互驱动的转场:

// 先把interactionController定义为实例属性
private var interactionController: UIPercentDrivenInteractiveTransition?

// 扩展实现导航控制器代理
extension YourViewController: UINavigationControllerDelegate {
    // 返回自定义动画控制器
    func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return YourCustomTransitionAnimator(operation: operation)
    }
    
    // 返回交互控制器,让导航控制器知道这是个交互转场
    func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
        return interactionController
    }
}

3. 手势方法的细节优化

调整手势处理逻辑,确保在调用pop前先创建好交互控制器,同时细化状态处理:

@objc private func handleEdgePanGesture(_ gestureRecognizer: UIScreenEdgePanGestureRecognizer) {
    guard let view = gestureRecognizer.view else { return }
    // 左边缘向右滑动时,translation.x为正,进度从0到1符合pop逻辑
    let progress = gestureRecognizer.translation(in: view).x / view.frame.size.width
    
    switch gestureRecognizer.state {
    case .began:
        // 先创建交互控制器,再触发pop
        interactionController = UIPercentDrivenInteractiveTransition()
        navigationController?.popViewController(animated: true)
    case .changed:
        interactionController?.update(progress)
    case .ended, .cancelled:
        let shouldFinish = progress >= 0.5
        shouldFinish ? interactionController?.finish() : interactionController?.cancel()
        interactionController = nil
    default:
        interactionController?.cancel()
        interactionController = nil
    }
}

最后别忘了在viewDidLoad里给导航控制器设置代理,并正确添加手势:

override func viewDidLoad() {
    super.viewDidLoad()
    navigationController?.delegate = self
    
    let edgePanGesture = UIScreenEdgePanGestureRecognizer(target: self, action: #selector(handleEdgePanGesture(_:)))
    edgePanGesture.edges = .left // 指定左边缘触发
    view.addGestureRecognizer(edgePanGesture)
}

这样调整后,左边缘滑动就能触发交互式的pop转场,不会再直接跳完整动画了。

内容的提问来源于stack exchange,提问作者Can

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:37:44