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
相关产品推荐
相关产品推荐

