Although not a view controller itself, the
UIPopoverController class manages the presentation of view controllers. You use a popover controller object to present content using a popover, which is a visual layer that floats above your app’s window. Popovers provide a lightweight way to present or gather information from the user and are commonly used in the following situations:
To display information about an object on the screen
To manage frequently accessed tools or configuration options
To present a list of actions to perform on objects inside one of your views
To present one pane from a split view controller when the device is in a portrait orientation
The use of a popover for the preceding actions is less intrusive and cumbersome than a modal view. In iPad apps, modal views should be reserved for situations where you require the user to explicitly accept or cancel some action or information. For example, you would use a modal view to ask the user for a password that granted access to the rest of your app. For most other cases, you would use a popover instead. The advantage of popovers is that they do not cover the entire screen and can be dismissed by simply tapping outside the popover view. Thus, they are an excellent choice in situations where user interactions with your content are not required but provide information or additional features for the user.
Figure 5-1 shows an example of a popover used to display a pane from a split view interface. Selecting a play from the popover causes the app’s main view to display information about that play. (For more information about creating a split view interface, see “Split View Controllers.”)
Creating and Presenting a Popover
The content of a popover is derived from a view controller object that you provide. Popovers are capable of presenting most types of view controllers. When you are ready to present that view controller in a popover, do the following:
Create an instance of the
UIPopoverControllerclass and initialize it with your view controller object.
Specify the size of the popover, which you can do in one of two ways:
(Optional) Assign a delegate to the popover. For more information about the responsibilities of the delegate, see “Implementing a Popover Delegate.”
Present the popover.
When you present a popover, you associate it with a particular portion of your user interface. Popovers are commonly associated with toolbar buttons, so the
presentPopoverFromBarButtonItem:permittedArrowDirections:animated: method is a convenient way to present popovers from your app’s toolbar. You can also associate a popover with a particular part of one of your views using the
The popover normally derives its initial size from the
contentSizeForViewInPopover property of the view controller being presented. The default size stored in this property is 320 pixels wide by 1100 pixels high. You can customize the default value by assigning a new value to the
contentSizeForViewInPopover property. Alternatively, you can assign a value to the
popoverContentSize property of the popover controller itself. If you change the view controller displayed by a popover, any custom size information you put in the
popoverContentSize property is replaced by the size of the new view controller. Changes to the content view controller or its size while the popover is visible are automatically animated. You can also change the size (with or without animations) using the
Listing 5-1 shows a simple action method that presents a popover in response to user taps in a toolbar button. The popover is stored in a property (defined by the owning class) that maintains a strong reference to the popover object. The size of the popover is set to the size of the view controller’s view, but the two need not be the same. Of course, if the two are not the same, you must use a scroll view to ensure the user can see all of the popover’s contents.
Listing 5-1 Presenting a popover programmatically
MyViewController* content = [[MyViewController alloc] init];
UIPopoverController* aPopover = [[UIPopoverController alloc]
aPopover.delegate = self;
// Store the popover in a custom property for later use.
self.popoverController = aPopover;
Popovers are dismissed automatically when the user taps outside the popover view. Taps within the popover do not cause it to be automatically dismissed, but you can dismiss it programmatically using the
dismissPopoverAnimated: method. You might do this when the user selects an item in your view controller’s content or performs some action that warrants the removal of the popover from the screen. If you do dismiss the popover programmatically, you need to store a reference to the popover controller object in a place where your view controller can access it. The system does not provide a reference to the currently active popover controller.
Implementing a Popover Delegate
When a popover is dismissed due to user taps outside the popover view, the popover automatically notifies its delegate of the action. If you provide a delegate, you can use this object to prevent the dismissal of the popover or perform additional actions in response to the dismissal. The
popoverControllerShouldDismissPopover: delegate method lets you control whether the popover should actually be dismissed. If your delegate does not implement the method, or if your implementation returns
YES, the controller dismisses the popover and sends a
popoverControllerDidDismissPopover: message to the delegate.
In most situations, you should not need to override the
popoverControllerShouldDismissPopover: method at all. The method is provided for situations where dismissing the popover might cause problems for your app. Rather than returning
NO from this method, though, it is better to avoid designs that require keeping the popover active. For example, it might be better to present your content modally and force the user to enter the required information or accept or cancel the changes.
By the time the
popoverControllerDidDismissPopover: method of your delegate is called, the popover itself has been removed from the screen. At this point, it is safe to remove existing references to the popover controller if you do not plan to use it again. You can also use this method to refresh your user interface or update your app’s state.
Tips for Managing Popovers in Your App
Consider the following when writing popover-related code for your app:
Dismissing a popover programmatically requires a pointer to the popover controller. The only way to get such a pointer is to store it yourself, typically in the content view controller. This ensures that the content view controller is able to dismiss the popover in response to appropriate user actions.
You can cache popover controllers and reuse them rather than creating new ones from scratch. Popover controllers are very malleable and so you can specify a different view controller and configuration options each time you use them.
When presenting a popover, specify the
UIPopoverArrowDirectionAnyconstant for the permitted arrow direction whenever possible. Specifying this constant gives the UIKit the maximum flexibility in positioning and sizing the popover. If you specify a limited set of permitted arrow directions, the popover controller may have to shrink the size of your popover before displaying it.