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

后端 未结 4 825
隐瞒了意图╮
隐瞒了意图╮ 2020-12-14 01:09

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 *         


        
相关标签:
4条回答
  • 2020-12-14 01:27

    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.

    0 讨论(0)
  • 2020-12-14 01:33

    Just adding this answer as an alternative way to present a popover from a touched cell, though it uses code rather than a segue. It's pretty simple though and has worked for me from iOS 4 through 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];
    }
    
    0 讨论(0)
  • 2020-12-14 01:34

    Swift answer using popoverPresentationController: Using storyboard, set up the new view controller with a Storyboard ID of 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
    
    }
    
    0 讨论(0)
  • 2020-12-14 01:46

    I have made this in the simplest way:

    1. Make this Popover Presentation Segue in Storyboard as usually but drag from ViewController (not button)
    2. select anchor view as table view
    3. then in table view cell's button touch make:

       private func presentCleaningDateDatePicker(from button: UIButton) {
          performSegue(withIdentifier: "Date Picker Popover Segue", sender: button)
      }
      
    4. and implement prepare(for segue) method

        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
              }
          }
      }
      
    0 讨论(0)
提交回复
热议问题