Presenting A Popover in iPad

The UIPopoverController class (for iPad) is a very neat way to present information to the user. In this blog, we’ll show how to use this class to present a popover view when the user touches a button. Let’s see how it works.

Start Xcode, click on “Create a new Xcode project,” and select the Single View Application template. Name the project PopoverDemo, and choose options as shown here:

Click Next, choose a location to save the project, and click Create.

We now have a single view application. Open ViewController.xib, and drag a UIButton to the view. Change its title to “Show Popover…” and also choose a color for the background of the view. When finished, the xib should look something like this:

In ViewController.h, make the following changes:

 

 

 

Notice that we’ve imported a view controller that does not yet exist: we’ll take care of that soon. We’ve also added an IBOutlet property for the button, as well as an action method. Wire up the property and method (in the ViewController.xib file) as shown:

We will now make a new view controller for our popover. In the navigator panel, select ViewController.xib, then right – click, and choose “New File…” Select the Objective-C Class template, click Next, name the new class PopoverViewController, and make sure that it is a subclass of UIViewController as shown:

Click Next, save the class in the default location, and click Create.

Now open PopoverViewController.xib, select the view, and delete it. (You cannot resize a view made by Xcode as a part of the view controller creation process.) Drag a new UIView from the library, and in the Size inspector, set the view’s properties as shown:

(The value of Height will not be used, the height of the popover will be configured by the system when it is displayed.)

Drag a Navigation Bar to the top of the view; also drag a UILabel onto the view. Set their texts as shown:

In this demo, we’ve also set the background color for the view. Now right – click the File’s Owner object, and drag from the circle to the right of “view” to the new View we’ve just created. This sets the View in interface builder as the PopoverViewController’s view property. (If we omit this step, the view controller cannot display the view!)

Open ViewController.m, and alter the file as shown:

 

 

 

Notice that the PopoverViewController (controller) and UIPopoverController (popoverController) objects are declared as iVars in the @interface section of the .m file, rather than properties. These iVars will not be exposed to any other class, nor should they be: they are private to the implementation of ViewController.

Let’s look first at viewDidLoad:. In this method, we instantiate both controller and popoverController. The controller object is an instance of our PopoverViewController class, we initialize it here with the nib name of the xib file, though initializing it with a nib name of nil would work as well. (Why? See the end of the blog for the answer…) After the controller is instantiated, we initialize popoverController with its contentViewController property set to the controller object.

In the showPopover: method, we respond to a touch on the button. If the popoverController is already shown, it is dismissed. Otherwise, we call presentPopoverFromRect: inView: permittedArrowDirections: animated:. The rectangle to use here is the frame of the object that summons the popover; in this case, the frame of the UIButton object. (This is the reason we set an outlet property to the button.) It is a good idea to use UIPopoverArrowDirectionAny as the value of the permittedArrowDirections argument: this ensures that wherever the system displays the popover, its arrow will always point to the control that summoned it.

In this demo, we’re not making any changes to the PopoverViewController class. We could place a button in the PopoverViewController.xib that calls a delegate method back to ViewController to dismiss the popover, but in this case, we simply rely on the fact that when the user touches outside the popover, it will be dismissed.

Run the application in both portrait and landscape mode:

There is nothing in our code that sets the behavior of the popover, except passing it the information about the button’s frame. In any orientation, the arrow of the popover will always point to the button, and the popover’s height and position will be adjusted to the best fit.

As for the answer to the question “why would a nib name of nil work just as well?”, in this case we created the nib file for PopoverViewController at the same time we created the controller. Since the controller has a nib (PopoverViewController.xib), nil tells the compiler to use the default nib: the one the controller was already associated with.

Of course, if we want to associate multiple nibs with a single controller, we can do that as well, but that is the subject of another blog…

Leave a Comment:

7 comments
Button in a popover will display text in the main view controller | Jisku.com - Developers Network says September 11, 2012

[…] By the way, I followed the tutorial here. […]

Reply
Jon Millar says October 5, 2012

Thanks soo much, Ive been looking precisely for this for ages!! The only worked examples I could get were for a pop over attached to a menu bar, not to a button. Im sooooooooooooooo grateful to you for letting me finally crack what the popover is doing here. Many thanks Jon

Reply
Kyle says January 16, 2013

Cool. how would I change the height of the popover though? I imagine a full height popover wouldn’t be too popular out there. Maybe I’m wrong though.

Reply
Kyle says January 16, 2013

Figured it out! Add this line of code to your viewDidLoad in PopoverViewController.m:

self.contentSizeForViewInPopover = CGSizeMake(300, 250);

Reply
miles says July 20, 2013

Hmmmm I’m having a tiny problem understanding the wire up process outlined here ->

“In this demo, we’ve also set the background color for the view. Now right – click the File’s Owner object, and drag from the circle to the right of “view” to the new View we’ve just created. This sets the View in interface builder as the PopoverViewController’s view property. (If we omit this step, the view controller cannot display the view!)”

This is what I’ve got so far ->

http://i.imgur.com/5mm8HaP.png

So which one are you talking about ???? Note the red arrows, which one are you referring to.

Also I think you’re referring to the file owner dialogue window in this description…and if so, note the blue boxes, I can’t right click those view circles you’re talking about … unless you’re referencing something else ???

Furthermore I’m using storyboards and want this to work with a textfield instead of a button, two text fields actually. Very similar to this ->

http://i.imgur.com/R6q0oJY.png

hoping that your solution will provide me with a method to doing this similar thing….

Reply
Marcelo Cantos says August 15, 2013

You don’t have to deconstruct the frame’s rectangle. Just write this:

CGRect popRect = self.btnShowPopover.frame;

In fact, you don’t even need the temporary. Just do this:

presentPopoverFromRect:self.btnShowPopover.frame

Reply
    Marcelo Cantos says August 15, 2013

    I just realised it’s even easier:

    presentPopoverFromRect:sender.frame

    Reply
Add Your Reply