paco8
paco8

Reputation: 83

Swift: Set UIBarButtonItem as source for popover WITHOUT tap?

I want to show a popover on iPad as soon as my view loads having as source a button on the top right corner. The popover displays properly on button tap, but I'm having trouble finding a way to display it without the button tap, when the page first loads. Is this possible?

This is what I have:

func displayOptions(sourceButton: UIBarButtonItem)
    let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
    if let popoverController = actionSheet.popoverPresentationController {
        var rect = CGRect(x: 0, y: 0, width: 0, height: 0)              
        popoverController.barButtonItem = sourceButton              
        popoverController.sourceRect = rect 
        popoverController.permittedArrowDirections = .up
    }
    viewController.present(actionSheet, animated: true, completion: nil)
}

This code works properly on button tap, but the app crashes if I try to call this function from viewDidLoad or viewDidAppear:

You must provide location information for this popover through the alert controller's popoverPresentationController. You must provide either a sourceView and sourceRect or a barButtonItem.

Upvotes: 1

Views: 1076

Answers (2)

JackDao
JackDao

Reputation: 513

Try using UIPopoverPresentationControllerDelegate

Code example:

  • viewDidLoad

    let buttonCustom = UIBarButtonItem(title: "Custom", style: .done, target: self, action: #selector(ViewController.customBarButtonAction))
    self.navigationItem.rightBarButtonItem  = buttonCustom
    displayOptions()
    
  • displayOptions

    func displayOptions() {
        let actionSheet = UIAlertController(title: "Title", message: "Message", preferredStyle: .actionSheet)
        if let popoverController = actionSheet.popoverPresentationController {
            let rect = CGRect(x: 0, y: 0, width: 0, height: 0)
            popoverController.sourceRect = rect
            popoverController.sourceView = self.view
            popoverController.permittedArrowDirections = .up
            popoverController.delegate = self
        }
        self.present(actionSheet, animated: true, completion: nil)
    }
    
  • using UIPopoverPresentationControllerDelegate

    func prepareForPopoverPresentation(_ popoverPresentationController: UIPopoverPresentationController) {
        popoverPresentationController.barButtonItem = self.navigationItem.rightBarButtonItem
    } 
    

Upvotes: 2

Harish
Harish

Reputation: 2512

  1. You need to provide the sourceView.
  2. UIAlertController must have a title, a message or an action to display.

    // Create a bar button item in ViewDidLoad.
    let button1 = UIBarButtonItem(image: UIImage(named: "imagename"), style: .plain, target: self, action: Selector("action"))
    self.navigationItem.rightBarButtonItem  = button1
    
    
    // Call in ViewDidLoad
    displayOptions(sourceButton: button1)
    
    func displayOptions(sourceButton: UIBarButtonItem) {
        let actionSheet = UIAlertController(title: "title", message: "message", preferredStyle: .actionSheet)
        if let popoverController = actionSheet.popoverPresentationController {
          let rect = CGRect(x: 0, y: 0, width: 0, height: 0)
          popoverController.barButtonItem = sourceButton
          popoverController.sourceRect = rect
          popoverController.sourceView = self.view
          popoverController.permittedArrowDirections = .up
        }
        self.present(actionSheet, animated: true, completion: nil)
    }
    

Upvotes: 0

Related Questions