2012-12-12 31 views
29

Tôi cần thực hiện phân đoạn Popover khi người dùng chạm vào một ô trong TableView động. Nhưng khi tôi cố gắng để làm điều này với mã này:Có thể thực hiện Phân đoạn Popover theo cách thủ công (từ ô UITableView động) không?

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

hơn tôi nhận được một lỗi:

trái phép cấu hình

Popover segue with no anchor

Có cách nào để làm điều này (để thực hiện một segue popover từ TableView động bằng tay)?

Trả lời

61

Tôi đã phải đối mặt với cùng một vấn đề này tối nay, có một vài cách giải quyết (bao gồm trình bày cửa sổ bật lên theo cách cũ thời).

Ví dụ này, tôi có một đối tượng được lưu trữ trong lớp ô tùy chỉnh của tôi. Khi ô được chọn, tôi gọi một hàm như thế này để mở chi tiết trong popOverViewController về đối tượng và trỏ (neo) đến ô tương ứng của nó trong bảng.

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

Vấn đề với phương pháp này là chúng tôi thường cần chế độ xem bật lên để có trình khởi tạo tùy chỉnh. Đây là vấn đề nếu bạn muốn xem của bạn được thiết kế trong storyboard thay vì một xib và có một phương thức init tùy chỉnh mà lấy các đối tượng liên quan đến ô của bạn như một tham số để sử dụng cho nó hiển thị. Bạn cũng không thể chỉ sử dụng một phân đoạn popover (ở cái nhìn đầu tiên) bởi vì bạn cần một điểm neo động (và bạn không thể neo vào một nguyên mẫu ô). Vì vậy, đây là những gì tôi đã làm:

  1. Trước tiên, tạo một 1px X 1px ẩn UIButton trong chế độ xem bộ điều khiển chế độ xem của bạn. (quan trọng để cung cấp cho các ràng buộc nút cho phép nó được di chuyển bất cứ nơi nào trong chế độ xem)
  2. Sau đó thực hiện một lối thoát cho nút (tôi gọi là popOverAnchorButton của tôi) trong trình điều khiển xem của bạn và kiểm soát kéo một segue từ nút ẩn đến xem bộ điều khiển bạn muốn phân biệt. Biến nó thành một phân khúc popOver.

Bây giờ bạn có một phân đoạn cửa sổ bật lên có neo 'hợp pháp'. Nút bị ẩn, vì vậy không ai có thể chạm vào nút đó một cách vô tình. Bạn chỉ sử dụng điều này cho một điểm neo.

Bây giờ, chỉ cần gọi segue theo cách thủ công trong chức năng của bạn như thế này.

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

Và ...... Thì đấy. Bây giờ bạn đang sử dụng phép thuật của phân biệt với tất cả sự vĩ đại của họ và bạn có một điểm neo động xuất hiện để trỏ đến ô của bạn. bây giờ trong -(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender bạn có thể chỉ đơn giản là gửi người gửi đến lớp của tế bào của bạn (cho rằng bạn làm kiểm tra thích hợp về loại người gửi và segue đang được gọi) và cung cấp cho đối tượng của segue destinationViewController đối tượng của ô.

Hãy cho tôi biết nếu điều này có ích hay bất kỳ ai có bất kỳ phản hồi hoặc cải tiến nào.

+7

Ngoài ra, nếu điều này giúp bạn. Nếu bạn có thể bình chọn nó. Tôi là một người dùng mới và cần phải kiếm được tín dụng nerd để làm bất cứ điều gì. – johnrechd

+0

Bạn có biết Xcode 5/iOS 7 có cải thiện gì trong lĩnh vực này không? Dù sao giải pháp tuyệt vời. – neural5torm

+0

Tôi không chắc chắn, mặc dù tôi không nghĩ như vậy. Tôi đang cập nhật ứng dụng sử dụng trong tuần tới cho iOS7 và sẽ cập nhật nếu cần. – johnrechd

3

Chỉ cần thêm câu trả lời này làm cách thay thế để hiển thị cửa sổ bật lên từ ô được chạm, mặc dù nó sử dụng mã thay vì một khoảng cách. Nó khá đơn giản và mặc dù đã làm việc cho tôi từ iOS 4 thông qua 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

câu trả lời Swift sử dụng popoverPresentationController: Sử dụng kịch bản, thiết lập bộ điều khiển xem mới với một Storyboard ID của 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

Điều này làm việc cho tôi bên trong một preparForSegue cho một phân đoạn popover quá. Tôi không phải chuyển đổi trực tràng hoặc thực hiện bất kỳ cách giải quyết cũ nào khác với chế độ xem 1x1 pt. Tôi cũng đặt sourceView trong bảng phân cảnh cho tableView. Điều này giúp với sự thích nghi trên chế độ xem chia nhỏ vì cửa sổ bật lên của tôi đã trượt chủ yếu ngoài màn hình khi chế độ xem chính bị ẩn trong các điều chỉnh đa nhiệm. – James

Các vấn đề liên quan