Search code examples
iosswiftuipopovercontrolleruipopoverpresentationcontroller

Popoverview is not centred on iPad rotation


In following code popover on iPad is not centred for second alert (cities) when iPad is rotated. It works fine for first alert (countries) though. I've printed the values and it's same for both alerts. It seems that despite having correct value for coordinates it doesn't present it in centre on device rotation for second alert.

Why it doesn't show in centre for second alert? How to fix it?

class MyVC: UIViewController {

    var popoverController:UIPopoverPresentationController?

    override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
        super.viewWillTransition(to: size, with: coordinator)

        self.tableView.reloadData()

        if self.popoverController != nil {
            popoverController?.sourceView = self.view
            print("viewWillTransition():width: x: \(UIScreen.main.bounds.size.width*0.5), y: \(UIScreen.main.bounds.size.height*0.5)")
            popoverController?.sourceRect = CGRect(x: UIScreen.main.bounds.size.width*0.5, y: UIScreen.main.bounds.size.height*0.5, width: 0, height: 0)
            popoverController?.permittedArrowDirections = []
        }
    }

    @IBAction func countryButtonClicked(_ sender: UIBarButtonItem) {
        displayCountries()
    }

    func displayCountries() {
        let alert = UIAlertController(title: "", message: "", preferredStyle: .actionSheet)

        let paragraphStyle = NSMutableParagraphStyle()
        paragraphStyle.alignment = .center

        let titleAttributedText = NSMutableAttributedString(
            string: "Select Country",
            attributes: [
                NSAttributedString.Key.paragraphStyle: paragraphStyle
            ]
        )
        alert.setValue(titleAttributedText, forKey: "attributedMessage")
        alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertAction.Style.cancel, handler: countryHandler))

        for list in Countries {
            alert.addAction(UIAlertAction(title: list, style: .default, handler: countryHandler))
        }

        // For iPad
        if let poController = alert.popoverPresentationController {
            popoverController = poController
            popoverController?.sourceView = self.view

            print("displayCountries():width: x: \(UIScreen.main.bounds.size.width*0.5), y: \(UIScreen.main.bounds.size.height*0.5)")
            popoverController?.sourceRect = CGRect(x: UIScreen.main.bounds.size.width*0.5, y: UIScreen.main.bounds.size.height*0.5, width: 0, height: 0)
            popoverController?.permittedArrowDirections = []
        }

        alert.view.addSubview(UIView())
        present(alert, animated: false, completion: nil)
    }

    @IBAction func cityButtonClicked(_ sender: Any) {
        showCities()
    }

    func showCities(){
        let alert = UIAlertController(title: "Select City", message: nil, preferredStyle: .actionSheet)

        for listItem in Cities {
            alert.addAction(UIAlertAction(title: listItem.title, style: .default, handler: cityHandler))
        }
        alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertAction.Style.cancel, handler: cityHandler))

        if let popoverController = alert.popoverPresentationController {
            popoverController.sourceView = self.view
            print("showCities():width: x: \(UIScreen.main.bounds.size.width*0.5), y: \(UIScreen.main.bounds.size.height*0.5)")
            popoverController.sourceRect = CGRect(x: UIScreen.main.bounds.size.width*0.5, y: UIScreen.main.bounds.size.height*0.5, width: 0, height: 0)
            popoverController.permittedArrowDirections = []
        }

        alert.view.addSubview(UIView())
        present(alert, animated: false, completion: nil)
    }
} 

Solution

  • popoverController must be also assigned in second alert:

    if let popoverController = alert.popoverPresentationController {
        self.popoverController = popoverController
    ...