Search code examples
iosswiftpopover

Avoid popover adapting to fullscreen in horizontally compact environment


According to documentation,

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

See below image. In compact environment, popover appear from bottom and animate to top until it covers the entire screen.

enter image description here

Is it possible to override this behaviour and have the popover only covering certain height of the screen as shown below?

enter image description here

Following code demonstrate the default behaviour of popover adapting to FullScreen presentation style in compact environment.

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.preferredContentSize = CGSize(width: 300, height: 200)
        popoverVC.modalPresentationStyle = .popover
        popoverVC.popoverPresentationController?.sourceView = sender
        popoverVC.popoverPresentationController?.permittedArrowDirections = .up
        self.present(popoverVC, animated: true, completion: nil)
    }
    
    
}

class PopoverViewController: UIViewController {
    override func viewDidLoad() {
        self.view.backgroundColor = .systemGray
    }
}

Output:

enter image description here


Solution

  • This feature is now available with iOS 15.

    Watch WWDC2021 short video

    Download WWDC sample project from here

     @IBAction func showImagePicker(_ sender: UIBarButtonItem) {
        
        let imagePicker = UIImagePickerController()
        imagePicker.delegate = self
        imagePicker.modalPresentationStyle = .popover
        if let popover = imagePicker.popoverPresentationController {
            popover.barButtonItem = sender
            
            let sheet = popover.adaptiveSheetPresentationController
            sheet.detents = [.medium(), .large()]
            sheet.largestUndimmedDetentIdentifier = .medium
            sheet.prefersScrollingExpandsWhenScrolledToEdge = false
            sheet.prefersEdgeAttachedInCompactHeight = true 
            sheet.widthFollowsPreferredContentSizeWhenEdgeAttached = true
        }
        
        present(imagePicker, animated: true, completion: nil)
    }