Swift: How to create a popup menu in iOS

12.2k views Asked by At

I'm doing some drawing on a custom UIView canvas, and rather than having a set of buttons at the bottom of the view to allow the user to select shapes, I'd like to have the user do a long press gesture, then have a popup-type menu appear with different shapes they can choose. I don't see anything like this in xCode, though I'd assume there's something like that in iOS. I don't want the alert popup that shows up when you have low battery and notifications.

I've looked into using a UIPopoverController but I'm a bit confused about some of the other Stack Overflow questions I've read about it, and also about the documentation given by Apple.

3

There are 3 answers

0
Chris McQueen On

I used Masture's method above and it worked for me (thank you!), but a couple of notes for other newbies like myself:

  1. Make sure you put "ShowMenuSegue" (or whatever you choose) as the identifier for your segue in the Storyboard, and

  2. I had to add

    var delegate: MainViewController!
    

    in the MenuViewController (with MainViewController being your source view controller) in order to get tvc.delegate = self to work

0
Pankaj Kulkarni On

Floating Menu

I described the steps to achieve floating menu as shown in above image:

  1. Create segue from the barButtonItem to the MenuViewCobtroller of type 'Present as Popover'
  2. In the MenuViewController override the preferredContentSize as:

    override var preferredContentSize : CGSize
    {
        get
        {
            return CGSize(width: 88 , height: 176)
        }
        set 
        {
            super.preferredContentSize = newValue
        }
    }
    

In my case I am returning CGSize with width 100 and size 200. You can set these values so as to fit your floating menu content properly. 4. In the initial/source view controller, in the prepare(for segue: sender) method set self as popoverPresentationController delegate:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "ShowMenuSegue" {
        if let tvc = segue.destination as? MenuViewController
        {
            tvc.delegate = self
            if let ppc = tvc.popoverPresentationController
            {
                ppc.delegate = self
            }
        }
    }
}

The source view controller must comply to UIPopoverPresentationControllerDelegate and implement following method:

extension ViewController: UIPopoverPresentationControllerDelegate {

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

That's it. You got the floating menu. Hopefully this will be useful.

0
Korpel On

After you make a connection of that button with the viewController and popover as a segue you will need to prepare. Here is the following code in order to prepare for the popover segue.

func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?)
{
    if let identifier = segue.identifier
    {
        switch identifier
        {
            case History.SegueIdentifier:

            if let tvc = segue.destinationViewController as? TextViewController
            {
                if let ppc = tvc.popoverPresentationController
                {
                    ppc.delegate = self
                }
                tvc.text = "\(diagnosticHistory)"
            }

            default: break
        }
    }
}

Do keep in mind that if you have an iPhone the popover will take full screen, so you can fix that using this for let's say a text that takes some particular elements.

This will fix the popover to be exactly the size of the elements you have in your text.

@IBOutlet weak var textView: UITextView!
{
    didSet
    {
        textView.text = text
    }
}

var text : String = ""
{
    didSet
    {
        textView?.text = text
    }
}

override var preferredContentSize : CGSize
{
    get
    {
        if textView != nil && presentingViewController != nil
        {
            return textView.sizeThatFits(presentingViewController!.view.bounds.size)
        }
        else
        {
            return super.preferredContentSize
        }
    }

    set {super.preferredContentSize = newValue}

    }
}

I have those 2 in different view controllers but I guess it will work. You will also need to implement UIPopoverPresentationControllerDelegate and

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

to your first viewController.