Is it possible to perform a Popover Segue manually (from dynamic UITableView cell)?

Hlib Dmytriiev picture Hlib Dmytriiev · Dec 12, 2012 · Viewed 18.1k times · Source

I need to perform a Popover segue when user touches a cell in a dynamic TableView. But when I try to do this with this code:

- (void)tableView:(UITableView *)tableview didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
        [self performSegueWithIdentifier:@"toThePopover" sender:[tableView cellForRowAtIndexPath]];
    //...
} 

than I get an error:

Illegal Configuration

Popover segue with no anchor

Is there any way to do this (to perform a popover segue from dynamic TableView manually)?

Answer

johnrechd picture johnrechd · Jan 25, 2013

I was faced with this same issue tonight, there a couple workarounds (including presenting the popover the old fashioned way).

For this example, I have an object that is stored in my custom cell class. When the cell is selected I call a function like this to open details in a popOverViewController about the object, and point (anchor) to it's corresponding cell in the table.

    - (void)openCustomPopOverForIndexPath:(NSIndexPath *)indexPath{
        CustomViewController* customView = [[self storyboard] instantiateViewControllerWithIdentifier:@"CustomViewController"];

        self.myPopOver = [[UIPopoverController alloc]
                                   initWithContentViewController:customView];
        self.myPopOver.delegate = self;
        //Get the cell from your table that presents the popover
        MyCell *myCell = (MyCell*)[self.tableView cellForRowAtIndexPath:indexPath];
        CGRect displayFrom = CGRectMake(myCell.frame.origin.x + myCell.frame.size.width, myCell.center.y + self.tableView.frame.origin.y - self.tableView.contentOffset.y, 1, 1);
        [self.myPopOver presentPopoverFromRect:displayFrom
                                             inView:self.view permittedArrowDirections:UIPopoverArrowDirectionLeft animated:YES];
    }

The problem with this method is that we often need the popover view to have a custom initializer. This is problematic if you want your view to be designed in storyboard instead of a xib and have a custom init method that takes your cells associated object as a parameter to use for it's display. You also can't just use a popover segue (at first glance) because you need a dynamic anchor point (and you can't anchor to a cell prototype). So here is what I did:

  1. First, create a hidden 1px X 1px UIButton in your view controllers view. (important to give the button constraints that will allow it to be moved anywhere in the view)
  2. Then make an outlet for the button (I called mine popOverAnchorButton) in your view controller and control drag a segue from the hidden button to the view controller you wish to segue to. Make it a popOver segue.

Now you have a popover segue with a 'legal' anchor. The button is hidden, so no one can touch it accidentally. You are only using this for an anchor point.

Now just call your segue manually in your function like this.

    - (void)openCustomPopOverForIndexPath:(NSIndexPath *)indexPath{
        //Get the cell from your table that presents the popover
        MyCell *myCell = (MyCell*)[self.tableView cellForRowAtIndexPath:indexPath];

        //Make the rect you want the popover to point at.
        CGRect displayFrom = CGRectMake(myCell.frame.origin.x + myCell.frame.size.width, myCell.center.y + self.tableView.frame.origin.y - self.tableView.contentOffset.y, 1, 1);

        //Now move your anchor button to this location (again, make sure you made your constraints allow this)
        self.popOverAnchorButton.frame = displayFrom;
        [self performSegueWithIdentifier:@"CustomPopoverSegue" sender:myCell];
    }

And...... Voila. Now you are using the magic of segues with all their greatness and you have a dynamic anchor point that appears to point to your cell. now in -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender you can simply cast the sender to your cell's class (given that you do the proper checks on sender type and which segue is being called) and give the segue's destinationViewController the cell's object.

Let me know if this helps, or anyone has any feedback or improvements.