Возможно ли выполнить Popover Segue вручную (из динамической ячейки UITableView)?

Мне нужно выполнить Popover segue, когда пользователь касается ячейки в динамическом TableView. Но когда я пытаюсь сделать это с помощью этого кода:

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

чем я получаю сообщение об ошибке:

Нелегальная конфигурация

Popover segue без привязки

Есть ли способ сделать это (для выполнения popover segue из динамического TableView вручную)?

Ответ 1

Сегодня я столкнулся с этой же проблемой, там были несколько обходных решений (в том числе представление старомодного стиля).

В этом примере у меня есть объект, который хранится в моем пользовательском классе ячейки. Когда ячейка выбрана, я вызываю функцию, подобную этой, чтобы открывать детали в popOverViewController об объекте и указывать (привязывать) к соответствующей ячейке в таблице.

    - (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];
    }

Проблема с этим методом заключается в том, что нам часто требуется представление popover для создания пользовательского инициализатора. Это проблематично, если вы хотите, чтобы ваше представление было спроектировано в раскадровке вместо xib, и у вас есть собственный метод инициализации, который связывает ваш объект с ячейками как параметр, который будет использоваться для его отображения. Вы также не можете просто использовать popover segue (на первый взгляд), потому что вам нужна динамическая опорная точка (и вы не можете привязываться к прототипу ячейки). Итак, вот что я сделал:

  • Сначала создайте скрытый 1px X 1px UIButton в вашем представлении контроллеров. (важно дать кнопки ограничения, которые позволят ему перемещаться в любом месте представления)
  • Затем сделайте выход для кнопки (я назвал my popOverAnchorButton) в вашем контроллере просмотра и управления перетащить segue из скрытой кнопки на контроллер вида, который вы хотите переместить. Сделайте его popOver segue.

Теперь у вас есть popover segue с "законным" якорем. Кнопка скрыта, поэтому никто не может коснуться ее случайно. Вы только используете это для точки привязки.

Теперь просто вызовите свой segue вручную в своей функции, как это.

    - (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];
    }

И...... Вуаля. Теперь вы используете магию segues со всем своим величием, и у вас есть динамическая опорная точка, которая, как представляется, указывает на вашу ячейку. теперь в -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender вы можете просто передать отправителя в свой класс ячеек (учитывая, что вы выполняете правильные проверки типа отправителя и который вызывается segue) и присваиваете segue destinationViewController объект ячейки.

Сообщите мне, если это поможет, или у кого-либо есть какие-либо отзывы или улучшения.

Ответ 2

Просто добавив этот ответ в качестве альтернативного способа представления popover из затронутой ячейки, хотя он использует код, а не segue. Это довольно просто, хотя и работал у меня от iOS 4 до iOS 7:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [tableView deselectRowAtIndexPath:indexPath animated:NO];

    //get the data of the row they clicked from the array
    Url* clickedRec = [self.resultsArray objectAtIndex:indexPath.row];

    //hide the popover in case it was already opened from a previous touch.    
    if (self.addNewPopover.popoverVisible) {
            [self.addNewPopover dismissPopoverAnimated:YES];
            return;
        }

    //instantiate a view controller from the storyboard
    AddUrlViewController *viewControllerForPopover =
    [self.storyboard instantiateViewControllerWithIdentifier:@"addUrlPopup"];

    //set myself as the delegate so I can respond to the cancel and save touches.
    viewControllerForPopover.delegate=self;
    //Tell the view controller that this is a record edit, not an add        
    viewControllerForPopover.addOrEdit = @"Edit";
    //Pass the record data to the view controller so it can fill in the controls            
    viewControllerForPopover.existingUrlRecord = clickedRec;

    UIPopoverController *popController = [[UIPopoverController alloc]
                                          initWithContentViewController:viewControllerForPopover];

    //keep a reference to the popover since I'm its delegate        
    self.addNewPopover = popController;

    //Get the cell that was clicked in the table. The popover arrow will point to this cell since it was the one that was touched.
    UITableViewCell *clickedCell = [self.tableView cellForRowAtIndexPath:indexPath];

    //present the popover from this cell frame.
    [self.addNewPopover presentPopoverFromRect:clickedCell.frame inView:self.myTableView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}

Ответ 3

Быстрый ответ с помощью popoverPresentationController: используя раскадровку, настройте новый контроллер представления с идентификатором раскадровки popoverEdit.

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

    let fromRect:CGRect = self.tableView.rectForRowAtIndexPath(indexPath)

    let popoverVC = storyboard?.instantiateViewControllerWithIdentifier("popoverEdit") as! UIViewController
    popoverVC.modalPresentationStyle = .Popover
    presentViewController(popoverVC, animated: true, completion: nil)
    let popoverController = popoverVC.popoverPresentationController
    popoverController!.sourceView = self.view
    popoverController!.sourceRect = fromRect
    popoverController!.permittedArrowDirections = .Any

}