当 iPad 旋转时,ActionSheet 的 PopoverController 不会停留在 window 的中心
ActionSheet's PopoverController doesn't stay in window's center when iPad is rotated
我有一个注销按钮,它显示一个操作 sheet,使用此代码将弹出框直接放在 window 中间的 iPad 上:
popoverController.sourceRect = CGRect(x: window.bounds.midX, y: window.bounds.midY, width: 0, height: 0)
popoverController.permittedArrowDirections = []
此处显示在window中间:
但是当我旋转 iPad 时,它会将自己定位到左下角:
为什么我旋转iPad时它不在window的中心?我该如何修复它以使其保持在旋转中心?
操作表:
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
}
}
}
您应该在设备旋转时更新框架:
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?
使用@omarzi 回答的一部分,我能够在将它与这个
结合使用时让它工作
正如 omarzi 所说,我必须创建一个变量来跟踪操作 sheet:
var actionSheet: UIAlertController?
我使用了上面链接的 SO Answer,就像 omarzi 的建议一样,它建议在设备旋转时更新框架,但答案是在 viewDidLayoutSubviews()
中更新它,如下所示:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let window = UIApplication.shared.windows.first(where: { [=11=].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)
}
我用这个方法解决了问题
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 扩展中。
我有一个注销按钮,它显示一个操作 sheet,使用此代码将弹出框直接放在 window 中间的 iPad 上:
popoverController.sourceRect = CGRect(x: window.bounds.midX, y: window.bounds.midY, width: 0, height: 0)
popoverController.permittedArrowDirections = []
此处显示在window中间:
但是当我旋转 iPad 时,它会将自己定位到左下角:
为什么我旋转iPad时它不在window的中心?我该如何修复它以使其保持在旋转中心?
操作表:
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
}
}
}
您应该在设备旋转时更新框架:
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?
使用@omarzi 回答的一部分,我能够在将它与这个
正如 omarzi 所说,我必须创建一个变量来跟踪操作 sheet:
var actionSheet: UIAlertController?
我使用了上面链接的 SO Answer,就像 omarzi 的建议一样,它建议在设备旋转时更新框架,但答案是在 viewDidLayoutSubviews()
中更新它,如下所示:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let window = UIApplication.shared.windows.first(where: { [=11=].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)
}
我用这个方法解决了问题
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 扩展中。