当 iPad 旋转时,ActionSheet 的 PopoverController 不会停留在窗口的中心
Posted
技术标签:
【中文标题】当 iPad 旋转时,ActionSheet 的 PopoverController 不会停留在窗口的中心【英文标题】:ActionSheet's PopoverController doesn't stay in window's center when iPad is rotated 【发布时间】:2018-05-04 17:45:28 【问题描述】:我有一个 logOut 按钮,它显示了一个操作表,该操作表使用以下代码将 iPad 上的弹出框直接置于窗口中间:
popoverController.sourceRect = CGRect(x: window.bounds.midX, y: window.bounds.midY, width: 0, height: 0)
popoverController.permittedArrowDirections = []
这里显示在窗口中间:
但是当我旋转 iPad 时,它会将自己定位在左下角:
为什么当我旋转 iPad 时它不停留在窗口的中心?如何修复它以使其保持旋转中心?
操作表:
fileprivate func logOut()
let actionSheet = UIAlertController(title: nil, message: "Are you sure you want to log out?", preferredStyle: .actionSheet)
let cancelActionButton = UIAlertAction(title: "Cancel", style: .destructive) (action) in
// ...
let logoutActionButton = UIAlertAction(title: "Log Out", style: .default) (action) in
// ...
actionSheet.addAction(logoutActionButton)
actionSheet.addAction(cancelActionButton)
if let popoverController = actionSheet.popoverPresentationController
popoverController.popoverBackgroundViewClass = PopoverBackgroundView.self
popoverController.sourceView = view
guard let window = UIApplication.shared.keyWindow else
popoverController.sourceView = view
popoverController.sourceRect = CGRect(x: view.bounds.midX, y: view.bounds.midY, width: 0, height: 0)
popoverController.permittedArrowDirections = []
return
window.backgroundColor = .clear
popoverController.sourceRect = CGRect(x: window.bounds.midX, y: window.bounds.midY, width: 0, height: 0)
popoverController.permittedArrowDirections = []
tabBarController?.present(actionSheet, animated: true, completion: nil)
UIPopoverBackgroundView 的子类:
class PopoverBackgroundView: UIPopoverBackgroundView
override init(frame: CGRect)
super.init(frame: frame)
backgroundColor = UIColor.white
convenience required init(coder aDecoder: NSCoder)
self.init(frame: CGRect.zero)
override func layoutSubviews()
super.layoutSubviews()
override var arrowOffset: CGFloat
get
return 0.0
set
override var arrowDirection: UIPopoverArrowDirection
get
return UIPopoverArrowDirection.up
set
override class func contentViewInsets() -> UIEdgeInsets
return UIEdgeInsetsMake(10.0, 10.0, 10.0, 10.0)
override class func arrowBase() -> CGFloat
return 0.0
override class func arrowHeight() -> CGFloat
return 0.0
override class var wantsDefaultContentAppearance: Bool
get
return false
【问题讨论】:
【参考方案1】:您应该在设备旋转时更新框架:
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator)
let bounds = UIApplication.shared.keyWindow?.bounds ?? view.bounds
currentActionSheet?.popoverPresentationController?.sourceRect = CGRect(x: bounds.midX, y: bounds.midY, width: 0, height: 0)
您需要将 UIAlertController 或 popoverController 保存到变量中
weak var currentActionSheet : UIAlertController?
【讨论】:
当我使它变弱并初始化到 logOut() 函数中的 actionSheet 时,actionSheet 保持为零并且不会初始化。此外,当我尝试覆盖 func viewWillTransition 时,我收到一条错误消息,提示“方法不会覆盖其超类中的任何方法”。当我删除覆盖 viewWillTransition 不起作用。我不得不使用这个答案; ***.com/a/42170419/4833705 让它工作。 你不直接初始化那个变量,因为它很弱,你应该给它赋值:currentActionSheet = actionSheet tabBarController?.present(actionSheet, animated: true, completion: nil) 阅读我刚刚发布的答案。如果您发现问题,我会将其删除并接受您的作为已接受的答案。【参考方案2】:使用@omarzi 答案的一部分,当我将它与SO Answer 结合使用时,我能够让它工作
就像 omarzi 说的,我必须创建一个变量来跟踪操作表:
var actionSheet: UIAlertController?
我使用了上面链接的 SO 答案,就像 omarzi 的建议一样,它建议在设备旋转时更新框架,但答案却是在 viewDidLayoutSubviews()
中更新它,如下所示:
override func viewDidLayoutSubviews()
super.viewDidLayoutSubviews()
if let window = UIApplication.shared.windows.first(where: $0.isKeyWindow )
let rect = CGRect(x: window.bounds.midX, y: window.bounds.midY, width: 0, height: 0)
actionSheet?.popoverPresentationController?.sourceRect = rect
这与答案是分开的,但响应@omarzi 在下面的评论中所说,完成后将 actionSheet 变量归零:
func presentActionSheet()
actionSheet = UIAlertController(title: nil, message: "Hello I'm an Action Sheet", preferredStyle: .actionSheet)
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) [weak self] (action) in
self?.actionSheet = nil
let someAction = UIAlertAction(title: "Do Something", style: .default) [weak self] (action) in
// do something
self?.actionSheet = nil
actionSheet?.addAction(someAction)
actionSheet?.addAction(cancelAction)
present(actionSheet!, animated: true, completion: nil)
【讨论】:
很高兴它对您有所帮助,因为您不会使用弱变量,因此当 UIAlertController 被解除时,您应该将强变量归零 我实际上打算这样做。谢谢您的帮助。我现在正在为你投票。【参考方案3】:我可以用这个方法解决问题
open override func viewWillLayoutSubviews()
super.viewWillLayoutSubviews()
if let window = UIApplication.shared.keyWindow
popoverPresentationController?.sourceRect = CGRect(x: window.bounds.midX, y: window.bounds.midY, width: 0, height: 0)
在我的 UIAlertController 扩展中。
【讨论】:
以上是关于当 iPad 旋转时,ActionSheet 的 PopoverController 不会停留在窗口的中心的主要内容,如果未能解决你的问题,请参考以下文章
如何在 iOS13 上的 iPad 上呈现 iPhone 风格的 actionSheet?
swift - 当设备旋转到横向(iPhone/iPad)时,如何让 UIView 变成全屏?
当 iPad 旋转时,UIPopovercontroller 不会保持在其位置