popoverPresentationController displaying modally from UITableViewController on iPhone

Viewed 624

I'm having an issue displaying a UIViewController with a popover presentation from iPhone within a UITableViewController. The code I have been using works to display a popover from any other UIViewController, just not a UITableViewController on iPhone. It does work from a UITableViewController on iPad.

When the code is executed, the view is presented modally temporarily (as you might expect if I did not implement adaptivePresentationStyleForPresentationController) and then covered by black, as if some sort of Auto Layout error occurred (though there's nothing in the console to indicate otherwise).

As I mentioned, the following works outside of a UITableViewController on iPhone, and works all the time on iPad. I'm sure I'm missing something fairly simple. Any ideas?

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    /* Create label */
    UILabel *label = [UILabel new];
    label.text = @"This should be in a popover.";
    label.numberOfLines = 0;
    label.lineBreakMode = NSLineBreakByWordWrapping;

    /* Add label to new ViewController */
    UIViewController *popoverVC = [UIViewController new];
    [popoverVC.view addSubview:label];
    label.translatesAutoresizingMaskIntoConstraints = NO;
    [popoverVC.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[label]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(label)]];
    [popoverVC.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-[label]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(label)]];

    /* Define ViewController to present as a popover and display */
    popoverVC.modalPresentationStyle = UIModalPresentationPopover;
    popoverVC.preferredContentSize = CGSizeMake(320, 50);
    [self presentViewController:popoverVC animated:YES completion:nil];

    /* Grab handle to ViewController's popoverPresentationController after displaying */
    UIPopoverPresentationController *popoverController = [popoverVC popoverPresentationController];
    if (popoverController == nil)
        NSLog(@"popoverController is nil");
    else {
        popoverController.delegate = self;
        popoverController.popoverLayoutMargins = UIEdgeInsetsMake(15, 15, 15, 15);
        popoverController.sourceView = tableView;
        popoverController.sourceRect = [tableView rectForRowAtIndexPath:indexPath];

        self.definesPresentationContext = YES;
    }
}

- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller traitCollection:(UITraitCollection *)traitCollection
{
    NSLog(@"%s", __PRETTY_FUNCTION__);
    return (UIModalPresentationNone);
}

FWIW: One way to quickly prototype this code is to add the above to MasterViewController.m from a new "Master-Detail Application" template in Xcode, and define this message to avoid pushing the DetailViewController:

- (BOOL)shouldPerformSegueWithIdentifier:(NSString *)identifier sender:(id)sender
{
    return (NO);
}

You'll also need to set MasterViewController.h to adopt the UIPopoverPresentationControllerDelegate protocol.

1 Answers
Related