是否可以手动执行Popover Segue(来自动态UITableView单元格)?

时间:2012-12-12 17:41:41

标签: ios uipopovercontroller segue

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

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

比我收到错误:

非法配置

  

Popover segue没有锚

有没有办法做到这一点(手动从动态TableView执行popover segue)?

4 个答案:

答案 0 :(得分:62)

今晚我遇到了同样的问题,有一些解决方法(包括用老式的方式呈现弹出窗口)。

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

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

  1. 首先,在视图控制器视图中创建一个隐藏的1px X 1px UIButton。 (重要的是给出按钮约束,允许它在视图中的任何位置移动)
  2. 然后在视图控制器中为按钮(我称之为popOverAnchorButton)创建一个插座,并控制将一个segue从隐藏按钮拖动到您想要切换到的视图控制器。把它变成一个popOver segue。
  3. 现在你有一个带有'合法'锚点的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];
        }
    

    而且......瞧。现在你正在使用segue的魔力和他们所有的伟大,你有一个动态的锚点,似乎指向你的细胞。 现在在-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender中,您可以简单地将发送者强制转换为您的单元格类(假设您对发送者类型进行了正确的检查以及正在调用哪个segue)并将segue的destinationViewController作为单元格的对象。

    如果这有帮助,或者任何人有任何反馈或改进,请告诉我。

答案 1 :(得分: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];
}

答案 2 :(得分:2)

使用popoverPresentationController快速回答:使用storyboard,设置一个故事板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

}

答案 3 :(得分: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
            }
        }
    }