Monday, April 11, 2011

Positioning the UIPopoverController after rotation

When creating applications for iPad, one of the most important feature we need to take into account is device orientation change. One issue that I came across while rotating a popover controller was maintaining the position of the popover controller after rotation.

So if you are at the stage where you still have to fight your popover controller to get it to behave, continue reading to know how I did it!

Here, we will consider showing the popover controller from a bar button.

Here's a recap for creating a popover controller:

1. Instantiate your nib file.
    MyNib * myNib = [[MyNib alloc] initWithNibName: @"MyNib" bundle: nil];

2. Get the instance of the bar button item from which the popover controller should be displayed:
    UIBarButtonItem *myBarButton = (UIBarButtonItem *)self.barButton;

3. Instantiate the popover controller and set the delegate
    self.myPopoverController = [[UIPopoverController alloc] initWithContentViewController: myNib];
     self.myPopoverController.delegate = self;


4. Set the size of the popover content controller
    [self.myPopoverController setPopoverContentSize: CGSizeMake(anyWidth, anyHeight)];

5. Finally present the popover
   [self.myPopoverController presentPopoverFromBarButtonItem: myBarButton
                                    permittedArrowDirections: UIPopoverArrowDirectionUp
                                                    animated: YES];


Put the above lines of code into a function called showMyPopover.

Now we come to the interesting part, handling the popover during rotation:

Override the didRotateFromInterfaceOrientation orientation handler like follows:

- (void) didRotateFromInterfaceOrientation: (UIInterfaceOrientation) fromInterfaceOrientation {
    if (self.myPopoverController) {
        [self.myPopoverController dismissPopoverAnimated: YES];
        [self.myPopoverController release];
        self.myPopoverController = nil;
    }

    [self showMyPopover];
}


And that's it, each time your orientation changes, your popover rotates appropriately.
If your popover controller contains a UITableViewController and you want to maintain state each time the UIPopoverController is rotated, have a look at my blog How to maintain the UITableView scrolled location

3 comments:

  1. The problem is that if the viewcontroller was maintaining state, you loose it.

    Almost better to disable rotation while the popover is visible in the shouldAutorotateToInterfaceOrientation function of the hosting. UIViewController.

    ReplyDelete
  2. self.myPopoverController = [[UIPopoverController alloc] initWithContentViewController: myNib];

    - assuming the property is "retain", in this line your controller retains the object twice.

    [self.myPopoverController release];
    self.myPopoverController = nil;

    - that's why here you have to release it twice.

    This is technically correct, but you'll have to explicitly release it every time you want to assign something else to the property.

    ReplyDelete
  3. cool, this is a solution for wrong position after rotation problem.

    ReplyDelete