简体   繁体   中英

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

Generally I followed the instructions here: https://stackoverflow.com/a/24687152/3741933 .

However, as discussed in its comments, the popover is always fullscreen regardless of preferredContentSize or sourceRect .

The button to present the popover:

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)
}

The 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.

It is possible! I'm not sure since when though...

In the viewDidLoad of your UIViewController that is displayed as a popover:

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

In the UIViewController that displays the popover, set the class as a UIPopoverPresentationControllerDelegate and:

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: In the storyboard, don't forget to set the segue kind as "Present As Popover"

That's it!

For those who are looking how to do without 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)
    }
}

Result on iPhone 11 Pro Max 👇

在此处输入图片说明

You can't do this in iPhone with portrait mode with this code ... you can check popover section in apple doc here..

It suggests that:

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.

And as I said, if you can check in iPad, your content can display inside a popover.

You just need to implement the next method of the UIPopoverPresentationControllerDelegate protocol:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM