简体   繁体   中英

Why is 'present as popover' segue covering the whole screen?

In my project I have a button on the bottom right side of the screen and i added another uiviewcontroller to the storyboard, did control-drag to the uiviewcontroller I wanted as the popover, then set that viewcontroller size to (300, 300) and checked 'use preferred explicit size'. When I load the app and click the button, the entire screen gets covered by the "popover". I also tried to go into the popoverViewController's .m file and set the size but that didn't work either.
Any ideas?

Edit: Since it looks like I have to have it be full screen that is fine however I am still running into some other problems I was having earlier. My popup screen will come up and I make the background black and alpha as .5 to make it see through however it'll do the animation, then once the animation is finished the screen will go from .5 opacity to completely black and the only thing I can see is the battery icon thing.

The OP uses Objective-C. This answer presents code in swift. Converting swift to Objective-C should be easy.

In the newly added ViewController, under “Simulated Metrics” change “Size” to “Freeform” and “Status Bar” to “None.”

Under “Simulated Size” change your view's height and width to the actual size you want your popover's content to be.

Create a segue to the newly added VC. Use segue type as "Present As Popover" and give a name for the segue, for example "popoverSegue".

In the ViewConroller from which this segue is to be triggered, add the UIPopoverPresentationControllerDelegate protocol.

class ViewController: UIViewController, UIPopoverPresentationControllerDelegate {
}

Override the prepareForSegue function to catch your popover segue. Set the modalPresentationStyle to .Popover to explicitly state that you want a popover and then assign the delegate property of the view's popoverPresentationController to self:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "popoverSegue" {
            let popoverViewController = segue.destinationViewController as! UIViewController
            popoverViewController.modalPresentationStyle = UIModalPresentationStyle.Popover
            popoverViewController.popoverPresentationController!.delegate = self
        }
    }

Implement the adaptivePresentationStyleForPresentationController function to tell your app that you really want that popover presentation and will accept no substitutions:

func adaptivePresentationStyleForPresentationController(controller: UIPresentationController) -> UIModalPresentationStyle {
        return UIModalPresentationStyle.None
    }

Following these, I could get a popup on iPhone which is not full screen but the size set for the ViewController.

在此处输入图片说明

Source: iPad Style Popovers on the iPhone with Swift

Thanks to Bharat for the great answer , I personally use a UIStoryboardSegue that does pretty much the same thing. That way, I can change the class of the segue in the storyboard, have what I want, and not pollute my controllers:

class AlwaysPopupSegue : UIStoryboardSegue, UIPopoverPresentationControllerDelegate
{
    override init(identifier: String?, source: UIViewController, destination: UIViewController)
    {
        super.init(identifier: identifier, source: source, destination: destination)
        destination.modalPresentationStyle = UIModalPresentationStyle.popover
        destination.popoverPresentationController!.delegate = self
    }
    func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
        return UIModalPresentationStyle.none
    }
}

Swift 3-5 version

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "SEGUE_IDENTIFIER" {
            let popoverViewController = segue.destination as! YourViewController
            
            popoverViewController.modalPresentationStyle = UIModalPresentationStyle.popover
            popoverViewController.popoverPresentationController!.delegate = self
        }
    }
    
    func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle {
        return UIModalPresentationStyle.none
    }
    

Swift 4 Version

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "SegueIdentifier" {
            let popoverViewController = segue.destination
            popoverViewController.modalPresentationStyle = .popover
            popoverViewController.presentationController?.delegate = self
     }
}

Don't forget to add

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

On iPhone you can creat a custom view controller that can manage all the popovers. Since each view controller has its own navigation controller, you can add a new view controller to the app.window.rootviewcontroller as a du view and bring all to front.

If you didn't want to write your own, you can use something like this for instance: http://cocoapods.org/pods/FPPopover

This is Swift 5 code, some/most of the above mentioned solutions are all valid. This is an effort to present whole solution. This example supposes you are using a xib for popover view controller but this would work otherwise as well, say, in prepare for segue. Here's a complete code:

Presenting ViewController:

let popoverVC = PopoverVC(nibName: "popoverVC", bundle: nil)
popoverVC.completionHandler = { [unowned self] (itemIndex : Int?) in
    if let itemIndex = itemIndex
    {
         // Do completion handling
    }
}

popoverVC.preferredContentSize = CGSize(width: 200, height: 60)
popoverVC.modalPresentationStyle = .popover

if let pvc = popoverVC.popoverPresentationController {
    pvc.permittedArrowDirections = [.down]
    pvc.delegate = self
    pvc.sourceRect = button.frame
    pvc.sourceView = button // Button popover is presented from
    present(popoverVC, animated: true, completion: nil)
}

This is important:

extension ViewController: UIPopoverPresentationControllerDelegate {
    func adaptivePresentationStyle(for controller: UIPresentationController) -> 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