iPhone 设备上的 Popover 显示样式 - 可能更多吗?

Popover presentation style on iPhone devices - possible any more?

我正在尝试定义附加到这样的视图的弹出视图:

这是我的代码:

class MyController: UIViewController, UIPopoverPresentationControllerDelegate {

    ...

    func displaySignOut(_ sender: UIButton) {
        let vc = UIStoryboard(name: "Main", bundle: nil)
            .instantiateViewController(withIdentifier: "signOutPopover")
        vc.modalPresentationStyle = .popover
        vc.preferredContentSize = CGSize(width: 100, height: 30)
        present(vc, animated: true, completion: nil)

        let pc = vc.popoverPresentationController!
        pc.sourceView = sender
        pc.sourceRect = sender.bounds
        pc.delegate = self
    }

    func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
        return .none
    }

    func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
        return .none
    }
}

因为弹出窗口太小了,所以我想在所有设备上使用这种样式。我遵循了将 adaptivePresentationStyle 覆盖为 return UIModalPresentationStyle.none 的通常建议(例如 here)。

这在 iPad 设备上工作正常,但在 iPhones 上,它不能。在较小的 iPhone 设备上,它会一直全屏显示。在较大的屏幕上(例如,iPhone 7 Plus),它出现错误,但奇怪的是,如果我在弹出窗口出现后旋转设备,则会切换到弹出窗口显示(纵向和横向)。 (如果我关闭弹出窗口并再次打开它,在我旋转设备之前它又是错误的。)此外,在横向模式下它出现在一个奇怪的配置中(不像在纵向模式下那样全屏):

与弹出窗口演示文稿不同,如果我在弹出窗口视图本身之外点击,这不会关闭。

Apple documentation 说(部分):

In a horizontally compact environment, popovers adapt to the UIModalPresentationOverFullScreen presentation style by default.

"by default" 强烈建议有一种方法可以覆盖此行为。但是(与 this post 一致),在委托中覆盖 adaptivePresentationStyle 似乎不再是执行此操作的方法(尽管它曾经有效)。那么有没有修改默认行为的新方法呢?

我正在使用 XCode 8.3.3 和 Swift 3.1,目标是 iOS 9+。

I have created one custom class with storyboard inside that connect outlet of button and implemented below code.

import UIKit
class PopOverViewController: UIViewController {

    @IBOutlet weak var button: UIButton!
    override func viewDidLoad() {
        super.viewDidLoad()
        button.backgroundColor = UIColor.purple
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    //Updating the popover size
    override var preferredContentSize: CGSize {
        get {
            let size = CGSize(width: 80, height: 60)
            return size
        }
        set {
            super.preferredContentSize = newValue
        }
    }


    //Setup the ViewController for popover presentation
    func updatePopOverViewController(_ button: UIButton?, with delegate: AnyObject?) {
        guard let button = button else { return }
        modalPresentationStyle = .popover
        popoverPresentationController?.permittedArrowDirections = [.any]
        popoverPresentationController?.backgroundColor = UIColor.purple
        popoverPresentationController?.sourceView = button
        popoverPresentationController?.sourceRect = button.bounds
        popoverPresentationController?.delegate = delegate
    }

}

And then Inside ViewController implemented one function to show popOver on iphone

func showPopOver(button: UIButton!) {
 let viewController = PopOverViewController()
 viewController.updatePopOverViewController(button, with: self)
  present(viewController, animated: true, completion: nil)
}

Note:- Tested and this should work on Portrait as well Landscape mode

iOS15有一些新的方法来解决这个问题。 查看 WWDC21 Session“在 UIKit 中自定义和调整工作表”https://developer.apple.com/wwdc21/10063 非常简单的弹出窗口和自定义工作表的新界面。展示如何与弹出框及其背后的视图进行non-modal交互。