Popovers

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:

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.)

Figure 5-1  Using a popover to display a master pane

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:

  1. Create an instance of the UIPopoverController class and initialize it with your view controller object.

  2. Specify the size of the popover, which you can do in one of two ways:

  3. (Optional) Assign a delegate to the popover. For more information about the responsibilities of the delegate, see Implementing a Popover Delegate.

  4. 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 presentPopoverFromRect:inView:permittedArrowDirections:animated: method.

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 setPopoverContentSize:animated: method.

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

- (IBAction)toolbarItemTapped:(id)sender
{
   MyViewController* content = [[MyViewController alloc] init];
   UIPopoverController* aPopover = [[UIPopoverController alloc]
        initWithContentViewController:content];
   aPopover.delegate = self;
 
   // Store the popover in a custom property for later use.
   self.popoverController = aPopover;
 
   [self.popoverController presentPopoverFromBarButtonItem:sender
        permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}

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: