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

Swift中如何使用多个UIPresentationController实现不同弹窗呈现效果

多UIPresentationController适配解决方案

问题1解决:解除TransitioningDelegate与当前ViewController的耦合

你的核心误区是默认必须把UIViewControllerTransitioningDelegate的实现写在触发弹窗的ViewController扩展中,该协议完全可以抽成独立的类实现,每一种弹窗样式对应单独的代理类即可,完全不需要耦合在当前ViewController上:

// 第一种弹窗对应的独立代理类
class Style1TransitionDelegate: NSObject, UIViewControllerTransitioningDelegate {
    func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
        PresentationController(presentedViewController: presented, presenting: presenting)
    }
    // 可补充对应样式的动画代理方法
}

// 第二种弹窗对应的独立代理类
class Style2TransitionDelegate: NSObject, UIViewControllerTransitioningDelegate {
    func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
        PresentationController2(presentedViewController: presented, presenting: presenting)
    }
    // 可补充对应样式的动画代理方法
}

调用时只需给要弹出的ViewController赋值对应代理即可,注意需要用属性持有代理实例(因为transitioningDelegate是weak属性,不持有会被释放导致失效):

// 触发第一种弹窗
let popup1 = PopupViewController1()
let delegate1 = Style1TransitionDelegate()
self.style1Delegate = delegate1 // 当前ViewController的属性持有
popup1.transitioningDelegate = delegate1
popup1.modalPresentationStyle = .custom
present(popup1, animated: true)

// 触发第二种弹窗
let popup2 = PopupViewController2()
let delegate2 = Style2TransitionDelegate()
self.style2Delegate = delegate2 // 当前ViewController的属性持有
popup2.transitioningDelegate = delegate2
popup2.modalPresentationStyle = .custom
present(popup2, animated: true)

该方案支持无限扩展弹窗样式,互不干扰,也不需要修改原有ViewController的代码。

问题2解决:语法错误修正

你提供的代码报错是Swift语法问题:只有单表达式的函数支持隐式省略return,多分支if else需要在每个分支显式加return,修正后代码如下:

extension ThirdViewControllerPassenger: UIViewControllerTransitioningDelegate {
    func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
        if something == something {
            return PresentationController(presentedViewController: presented, presenting: presenting)
        } else {
            return PresentationController2(presentedViewController: presented, presenting: presenting)
        }
    }
}

也可以用三目运算符简化:

extension ThirdViewControllerPassenger: UIViewControllerTransitioningDelegate {
    func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
        something == something ? PresentationController(presentedViewController: presented, presenting: presenting) : PresentationController2(presentedViewController: presented, presenting: presenting)
    }
}

但该方案耦合了不同弹窗的逻辑,扩展性不如独立代理类的方案。

问题3解决:放弃全局状态存储的方案

UserDefaults读不到值大概率是写入后同步时序异常导致,且用全局状态传参的实现稳定性极差,完全可以通过自定义构造器直接传参解决:

// 定义样式枚举
enum PopupStyle {
    case tripOverview
    case normalCard
}

// 自定义UIPresentationController新增构造参数
class CustomPresentationController: UIPresentationController {
    private let style: PopupStyle
    
    init(presentedViewController: UIViewController, presenting: UIViewController?, style: PopupStyle) {
        self.style = style
        super.init(presentedViewController: presentedViewController, presenting: presenting)
    }
    
    // 后续逻辑直接读取self.style判断即可,不需要访问全局状态
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 19:36:03