30

当用户触摸动态 TableView 中的单元格时,我需要执行 Popover segue。但是当我尝试使用此代码执行此操作时:

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

比我得到一个错误:

非法配置

Popover segue 没有锚点

有什么方法可以做到这一点(手动从动态 TableView 执行弹出框转场)?

4

4 回答 4

61

今晚我遇到了同样的问题,有几个解决方法(包括以老式方式呈现弹出框)。

对于此示例,我有一个对象存储在我的自定义单元类中。当单元格被选中时,我调用这样的函数来打开 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];
    }

这种方法的问题是我们经常需要弹出视图有一个自定义的初始化器。如果您希望在情节提要而不是 xib 中设计视图并且有一个自定义 init 方法将您的单元格关联对象作为参数用于它的显示,那么这是有问题的。您也不能只使用 popover segue(乍一看),因为您需要一个动态锚点(并且您不能锚定到单元原型)。所以这就是我所做的:

  1. 首先,在您的视图控制器视图中创建一个隐藏的 1px X 1px UIButton。(重要的是要给出允许它在视图中移动的任何地方的按钮约束)
  2. 然后在您的视图控制器中为按钮(我称为 popOverAnchorButton)制作一个插座,并控制将一个 segue 从隐藏按钮拖动到您希望 segue 的视图控制器。让它成为一个popOver segue。

现在你有了一个带有“合法”锚的弹出框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 提供给单元格的对象。

让我知道这是否有帮助,或者任何人有任何反馈或改进。

于 2013-01-25T03:24:24.343 回答
3

只需添加此答案作为从触摸单元格呈现弹出窗口的替代方法,尽管它使用代码而不是 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's 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's frame.
    [self.addNewPopover presentPopoverFromRect:clickedCell.frame inView:self.myTableView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
}
于 2014-06-30T14:58:57.543 回答
2

使用 popoverPresentationController 快速回答:使用情节提要,设置新的视图控制器,情节提要 ID 为 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

}
于 2015-08-03T07:22:22.350 回答
0

我以最简单的方式做到了这一点:

  1. 像往常一样在 Storyboard 中制作这个 Popover Presentation Segue,但从 ViewController 拖动(不是按钮)
  2. 选择锚视图作为表格视图
  3. 然后在表格视图单元格的按钮触摸中:

     private func presentCleaningDateDatePicker(from button: UIButton) {
        performSegue(withIdentifier: "Date Picker Popover Segue", sender: button)
    }
    
  4. 并实现 prepare(for segue) 方法

      override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    
        if let identifier = segue.identifier {
            switch identifier {
            case "Date Picker Popover Segue":
    
                if let vc = segue.destination as? DatePickerViewController {
                    if let ppc = vc.popoverPresentationController {
                        ppc.sourceView = sender as! UIButton
                        ppc.sourceRect = (sender as! UIButton).frame
                        ppc.delegate = vc
    
                        vc.minimumDate = Date()
                        vc.maximumDate = Date().addMonth(n: 3)
                        vc.delegate = self
                    }
                }
            default:
                break
            }
        }
    }
    
于 2018-05-18T08:41:56.937 回答