iOS17 TipKit(UIKit):点击提示Popover外部关闭的检测问题
解决UIKit中TipKit提示Popover外部关闭事件捕获问题
针对你遇到的点击TipKit Popover外部关闭时无法触发后续提示的问题,可以通过监听Tip的展示状态变化来实现,无需依赖ViewController的 dismissal 代理或isBeingDismissed属性,具体方案如下:
核心思路
TipKit的Tip结构体本身支持通过Observation监听其isDisplayed属性变化,无论用户是点击关闭按钮还是点击外部区域关闭Popover,只要提示从显示状态变为隐藏,就能捕获到这个变化,进而触发第二个提示的展示条件。
具体实现步骤
调整Tip结构体的触发规则
确保FreezeTip的显示规则可被外部状态控制,示例如下:struct FreezeTip: Tip { @Parameter static var pauseTipDisplayed: Bool = false var title: Text { Text("冻结操作提示") } var rules: [Rule] { #Rule(Self.$pauseTipDisplayed) { $0 == true } } }在ViewController中监听第一个Tip的状态
在主ViewController中,为PauseTip添加状态监听,当它从显示变为隐藏时,触发第二个提示的展示条件:class MainViewController: UIViewController { private let pauseTip = PauseTip() private var tipObservation: AnyCancellable? override func viewDidLoad() { super.viewDidLoad() // 初始化TipKit配置 try? Tips.configure([.displayFrequency(.immediate)]) // 监听PauseTip的显示状态变化 tipObservation = pauseTip.$isDisplayed .removeDuplicates() .sink { [weak self] isDisplayed in guard let self = self else { return } // 提示从显示转为隐藏时,触发第二个提示 if !isDisplayed { FreezeTip.pauseTipDisplayed = true // 手动触发第二个提示展示(可选,确保即时生效) Task { try? await Tips.show(FreezeTip(), in: self.view) } } } // 展示第一个提示 Task { try? await Tips.show(pauseTip, in: view) } } }
为什么之前的方案失效?
isBeingDismissed检测:TipKit的Popover由系统内部的TipUIPopoverViewController管理,点击外部关闭时,该控制器的状态不会同步到你的主ViewController,因此无法通过isBeingDismissed捕获事件。presentationControllerDidDismiss代理:TipUIPopoverViewController属于iOS17私有API,无法直接持有其实例并设置代理,导致代理方法无法触发。
额外优化
若无需依赖Parameter触发,也可直接在监听回调中调用Tips.show()展示第二个提示,跳过参数同步环节,避免状态延迟问题。
内容的提问来源于stack exchange,提问作者rafi
相关产品推荐
相关产品推荐

