如何在 iPhone 上以编程方式在 Swift 中将 UIViewController 呈现为弹出窗口

How to present a UIViewController as a popover in Swift programmatically on iPhone

通常我遵循这里的说明:。

但是,正如其评论中所讨论的,无论 preferredContentSize 还是 sourceRect,弹出窗口始终是全屏的。

显示弹出窗口的按钮:

func buttonClicked(sender: UIButton!) {
    let ac = EmptyViewController() as UIViewController
    ac.modalPresentationStyle = .Popover
    ac.preferredContentSize = CGSizeMake(200, 200)
    let popover = ac.popoverPresentationController
    popover?.delegate = self
    popover?.permittedArrowDirections = .Any
    popover?.sourceView = self.view
    popover?.sourceRect = CGRect(x: 100, y: 100, width: 100, height: 100)

    presentViewController(ac, animated: true, completion: nil)
}

UIViewController:

import UIKit

class EmptyViewController : UIViewController {
    override func viewDidLoad() {
        view.backgroundColor = UIColor.redColor()
    }
}

I am wondering how to make it a real popover (not full screen size). By the way, as @EI Captain indicated, it works perfectly on iPad but always fullscreen on iPhone.

您不能在 iPhone 中使用此代码在纵向模式下执行此操作...您可以查看 popover section in apple doc here..

这表明:

In iOS 8 and later, you use a UIPopoverPresentationController to present a popover. UIPopoverPresentationController defines a delegate that lets you adjust the display style of your popover content to suit the current display environment. For example, in a horizontally regular environment, your content can display inside a popover; in a horizontally compact environment, your content can display in a full-screen modal view.

正如我所说,如果您可以签入 iPad,您的内容可以显示在弹出框内。

有可能!我不确定从什么时候开始...

在显示为弹出窗口的 UIViewControllerviewDidLoad 中:

    self.preferredContentSize = CGSize(width: myWidth, height: myHeight)

在显示弹出窗口的 UIViewController 中,将 class 设置为 UIPopoverPresentationControllerDelegate 并且:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

    if segue.identifier == "Identifier" {
        let vc: UIViewController = segue.destination

        let pvc = vc.popoverPresentationController
        pvc?.delegate = self
        return
    }

}

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

PS:在storyboard中,不要忘记设置segue kind为"Present As Popover"

就是这样!

对于那些正在寻找如何不使用 segue 的人

import UIKit

class ViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        self.view.backgroundColor = .systemBackground
        
        let button = UIButton()
        button.translatesAutoresizingMaskIntoConstraints = false
        button.setImage(UIImage(systemName: "square.grid.2x2.fill"), for: .normal)
        button.addTarget(self, action: #selector(displayPopover), for: .touchUpInside)
        self.view.addSubview(button)
        
        NSLayoutConstraint.activate([
            button.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 100),
            button.centerXAnchor.constraint(equalTo: self.view.centerXAnchor),
            button.widthAnchor.constraint(equalToConstant: 40),
            button.heightAnchor.constraint(equalToConstant: 40),
        ])
        
    }
    
    @IBAction func displayPopover(sender: UIButton!) {
        let popoverVC = PopoverViewController()
        popoverVC.modalPresentationStyle = .popover
        popoverVC.popoverPresentationController?.sourceView = sender
        popoverVC.popoverPresentationController?.permittedArrowDirections = .up
        popoverVC.popoverPresentationController?.delegate = self
        self.present(popoverVC, animated: true, completion: nil)
    }
}

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

class PopoverViewController: UIViewController {
    override func viewDidLoad() {
        self.view.backgroundColor = .systemGray
        self.preferredContentSize = CGSize(width: 300, height: 200)
    }
}

结果 iPhone 11 Pro Max

你只需要实现UIPopoverPresentationControllerDelegate协议的下一个方法:

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