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

iPad旋转时ActionSheet的PopoverController无法保持窗口居中问题咨询

为什么iPad旋转后Popover无法保持在窗口中央?

这个问题我之前也踩过坑!核心原因很简单:你一开始设置的sourceRect是基于旋转前的窗口尺寸计算的中心,而iPad旋转后,窗口的bounds会发生宽高互换的变化,但iOS的Popover控制器不会自动帮你重新计算更新这个位置——它只会记住你第一次设置的坐标,旋转后这个坐标就不再对应新窗口的中心,自然就跑偏到左下角了。

解决方法:监听旋转事件,实时更新Popover位置

你需要在设备旋转时,重新获取新窗口的中心坐标,更新Popover的sourceRect。这里有两种靠谱的实现方式:

1. 利用视图控制器的生命周期方法

在你展示Popover的视图控制器里,重写viewWillTransition(to:with:)方法——这个方法会在设备旋转、窗口尺寸变化前被调用,刚好适合我们更新位置:

// 先给CGRect加个扩展,方便快速获取中心坐标
extension CGRect {
    var center: CGPoint {
        CGPoint(x: midX, y: midY)
    }
}

// 在你的视图控制器里
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransition(to: size, with: coordinator)
    
    // 确保你持有Popover对应的AlertController引用
    guard let alertController = yourActionSheetAlertController,
          let popoverController = alertController.popoverPresentationController,
          let keyWindow = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) else {
        return
    }
    
    // 计算新窗口的中心,更新sourceRect
    let newWindowCenter = keyWindow.bounds.center
    popoverController.sourceRect = CGRect(x: newWindowCenter.x, y: newWindowCenter.y, width: 0, height: 0)
    
    // 强制Popover更新布局,确保位置生效
    coordinator.animate(alongsideTransition: { _ in
        popoverController.containerView?.layoutIfNeeded()
    })
}

2. 监听设备旋转通知

如果你的场景不适合用视图控制器的生命周期方法,也可以注册旋转通知,在回调里更新位置:

override func viewDidLoad() {
    super.viewDidLoad()
    // 注册旋转通知
    NotificationCenter.default.addObserver(self, selector: #selector(updatePopoverPosition), name: UIDevice.orientationDidChangeNotification, object: nil)
}

@objc private func updatePopoverPosition() {
    guard let alertController = yourActionSheetAlertController,
          let popoverController = alertController.popoverPresentationController,
          let keyWindow = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) else {
        return
    }
    
    let newWindowCenter = keyWindow.bounds.center
    popoverController.sourceRect = CGRect(x: newWindowCenter.x, y: newWindowCenter.y, width: 0, height: 0)
}

// 记得在视图销毁时移除通知
deinit {
    NotificationCenter.default.removeObserver(self)
}

额外注意点

  • 一定要持有ActionSheet对应的UIAlertController引用,不然你没法在旋转时拿到它的popoverPresentationController。
  • 你之前设置的permittedArrowDirections = []是正确的,这样Popover就不会显示箭头,完全居中展示。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 11:09:36