【问题标题】:How to correctly present a popover from a UITableViewCell with UIPopoverArrowDirectionRight or UIPopoverArrowDirectionLeft如何使用 UIPopoverArrowDirectionRight 或 UIPopoverArrowDirectionLeft 从 UITableViewCell 正确呈现弹出框
【发布时间】:2011-03-02 05:15:48
【问题描述】:

我总是尝试以这种方式从 tableView 中的单元格呈现弹出框:

[myPopover presentPopoverFromRect:cell.frame inView:self.tableView permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];

但我不能使用 UIPopoverArrowDirectionRight 或 Left,因为取决于位置 ipad(纵向或横向),弹出框出现在其他地方。

我是否以正确的方式呈现弹出框?

PS:table view在一个splitView的detailView中。

【问题讨论】:

  • 如何实例化 myPopover?

标签: objective-c ipad uipopovercontroller popover


【解决方案1】:

单元格框架将类似于 0,0,width,size,我不相信它的 X 和 Y 相对于 tableView...你想使用 - (CGRect)rectForRowAtIndexPath:(NSIndexPath * )indexPath 为此,这应该会为您返回相对于 tableView 的单元格的正确框架...这是一个链接 UITAbleView ref

【讨论】:

  • 嘿!感谢您的回答.. 但是使用您推荐的方法,我得到了相同的 CGrect,但弹出框的位置仍然存在问题。当 ipad 处于纵向模式时,当我指定这些箭头方向时,弹出框会出现在屏幕的左上角......它吓坏了我!!! ..另一方面,从self.TableView呈现它是否正确?还是谢谢你
【解决方案2】:

我遇到了同样的问题,这是我使用的解决方法:

  • 在我的 UITableViewCell 中,我为单元格的特定按钮添加了操作(IBActions,因为我从 NIB 生成我的单元格)。
  • 然后我定义了一个模仿我的动作选择器的 CellActionDelegate 协议,我有我的按钮(发送者)和我的单元格(自我)
  • 然后我的 splitViewController 的 detailViewController 实现了这个协议,将单元格的坐标转换为它的坐标...

这里是代码示例

在 MyCustomTableViewCell.m 中:

   -(IBAction)displaySomeCellRelativePopover:(id)sender{
        //passes the actions to its delegate
        UIButton *button = (UIButton *)sender;
        [cellActionDelegate displaySomeCellRelativePopoverWithInformation:self.info
                                                               fromButton:button 
                                                                 fromCell:self];   
   }

还有,在 MyDetailViewController.m 中:

-(void)displaySomeCellRelativePopoverWithInformation:(MyCellInformationClass *)info
                                          fromButton:(UIButton *)button 
                                            fromCell:(UIView *)cell{

UIPopoverController * popoverController = nil;

//create your own UIPopoverController the way you want

//Convert your button/view frame

CGRect buttonFrameInDetailView = [self.view convertRect:button.frame fromView:cell];

//present the popoverController
[popoverController presentPopoverFromRect:buttonFrameInDetailView
                               inView:self.view permittedArrowDirections:UIPopoverArrowDirectionRight animated:YES];]


//release objects created...
}

PS:当然,“动作”不一定是 IBAction,弹出框的来源也不一定是 UIButton - 单个 UIView 会很好:)

【讨论】:

  • 嘿..谢谢,我会试一试..这似乎是一个聪明的解决方法jeje
【解决方案3】:

我也遇到过这个问题。我的一个解决方案是简单地更改 CGRect)rectForRowAtIndexPath:(NSIndexPath *)indexPath 返回的矩形的宽度:

CGRect rect = [aTableView rectForRowAtIndexPath:indexPath];

//create a 10 pixel width rect at the center of the cell

rect.origin.x = (rect.size.width - 10.0) / 2.0; 
rect.size.width = 10.0;  

[self.addExpensePopoverController presentPopoverFromRect:rect inView:aTableView permittedArrowDirections:UIPopoverArrowDirectionAny  animated:YES]; 

这会在单元格内创建一个居中的矩形。这样一来,popover 就有更多机会找到合适的位置。

【讨论】:

  • 我使用此方法将 ActionSheet 附加到 iPad 上 tableviewcell 的 detailText。 CGRect rectToUse = targetCell.bounds; rectToUse.origin.x = rectToUse.size.width - 200; rectToUse.size.width -= rectToUse.origin.x;
【解决方案4】:

您通过 rectForRowAtIndexPath 方法从单元格中获取框架。这是对的。然而,tableview 很可能是较大 iPad 视图的子视图,因此当弹出框获取坐标时,它认为它们在较大的视图中。这就是弹出框出现在错误位置的原因。

例如,行的 CGRect 是 (0,40,320,44)。它不是针对 tableview 上的该框架的弹出框,而是针对您的主视图上的该框架。

我通过将框架从表格的相对坐标转换为大视图中的坐标解决了这个问题。

代码:

CGRect aFrame = [self.myDetailViewController.tableView rectForRowAtIndexPath:[NSIndexPath indexPathForRow:theRow inSection:1]];
[popoverController presentPopoverFromRect:[self.myDetailViewController.tableView convertRect:aFrame toView:self.view] inView:self.view permittedArrowDirections:UIPopoverArrowDirectionRight animated:YES];

希望能帮助其他搜索此问题的人。

【讨论】:

  • 这解决了我在纵向工作但不能在横向工作的问题。谢谢
  • 这绝对有帮助。我从单元格本身获取框架,[tableView cellForRowAtIndexPath:indexPath],这是一件坏事。甚至不知道-rectForRowAtIndexPath:。谢谢!
  • 很好的答案:D
  • swift 3: [self.tableView .rectForRow(at: indexPath)];
【解决方案5】:

我今天遇到了这个问题,我找到了一个更简单的解决方案。
实例化弹出框时,需要指定单元格的内容视图:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    UIViewController *aViewController = [[UIViewController alloc] init];
    // initialize view here

    UIPopoverController *popoverController = [[UIPopoverController alloc] 
        initWithContentViewController:aViewController];
    popoverController.popoverContentSize = CGSizeMake(320, 416);
    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    [popoverController presentPopoverFromRect:cell.bounds inView:cell.contentView 
        permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];

    [aView release];
    // release popover in 'popoverControllerDidDismissPopover:' method
}

【讨论】:

  • 只是一个问题,你能用那个方法只用一个 UIVew 实例化一个 UIPopoverController 吗?生病;试试看 =D
  • @Omer 不确定你的意思。你能澄清一下吗?
  • 这是正确的答案。 presentPopoverFromRect 的文档说 rect 是视图中用于锚定弹出窗口的矩形,而视图是包含弹出框的锚矩形的视图,因此它实际上比看起来更简单!
  • 使用 UIView 启动一个 UIPopovercontroller 会在你尝试执行时给你一个警告和一个 NSInvalidArgumentException。你应该把它放在一个 UIViewController 中,然后启动 popovercontroller。
【解决方案6】:

这是对我来说很好的简单解决方案

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {

    UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
    CGRect rect=CGRectMake(cell.bounds.origin.x+600, cell.bounds.origin.y+10, 50, 30);
    [popOverController presentPopoverFromRect:rect inView:cell permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];

}

【讨论】:

  • 这表示显示矩形的原点在单元格边界原点右侧 600 处(从单元格原点顶部向下 10 处)。您可以调整这些以将演示文稿放置在单元格内的任何位置。
  • 大多数人不应该这样做。永远不要使用这样的硬编码数字,当方向改变时这将不起作用。
  • 我们不应该硬编码rect的x值,因为我们有不同分辨率的设备
【解决方案7】:

要在附件旁边弹出一个弹出窗口,您可以使用此代码:)

我将它用于更多高级用途:

  1. 找到自定义的 accesoryView (cell.accesoryView)
  2. 如果为空,则查找生成的accesoryView(UIButton)如果单元格有
  3. 如果 UIButton 不存在,则查找单元格内容视图 (UITableViewCellContentView)
  4. 如果单元格内容视图不存在,请使用单元格视图

可用于 UIActionSheetUIPopoverController

这是我的代码:

UIView *accessoryView       = cell.accessoryView; // finds custom accesoryView (cell.accesoryView)
if (accessoryView == nil) {
    UIView *cellContentView = nil;

    for (UIView *accView in [cell subviews]) {
        if ([accView isKindOfClass:[UIButton class]]) {
            accessoryView   = accView; // find generated accesoryView (UIButton) 
            break;
        } else if ([accView isKindOfClass:NSClassFromString(@"UITableViewCellContentView")]) {
            // find generated UITableViewCellContentView                
            cellContentView = accView; 
        }
    }
    // if the UIButton doesn't exists, find cell contet view (UITableViewCellContentView)           
    if (accessoryView == nil) { 
        accessoryView   = cellContentView; 
    }
    // if the cell contet view doesn't exists, use cell view
    if (accessoryView == nil) {
        accessoryView   = cell; 
    }
}

[actionSheet showFromRect:accessoryView.bounds inView:accessoryView animated:YES];

在 iOS 4.3 到 5.1 中测试

最好用作自定义方法:

-(UIView*)getViewForSheetAndPopUp:(UITableViewCell*)cell;

及方法代码:

-(UIView*)getViewForSheetAndPopUp:(UITableViewCell*)cell {
UIView *accessoryView = cell.accessoryView;

if (accessoryView == nil) {
    UIView *cellContentView = nil;

    for (UIView *accView in [cell subviews]) {
        if ([accView isKindOfClass:[UIButton class]]) {
            accessoryView = accView;
            break;
        } else if ([accView isKindOfClass:NSClassFromString(@"UITableViewCellContentView")]) {              
            cellContentView = accView;
        }
    }       

    if (accessoryView == nil) {
        accessoryView   = cellContentView;
    }
    if (accessoryView == nil) {
        accessoryView   = cell;
    }
}

return accessoryView;
}

【讨论】:

  • 经过测试在 iOS6SDK 中工作。我没有尝试自定义的方法,只是在ViewController的-(void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath
【解决方案8】:

这就是我所做的并且工作得很好。

RidersVC *vc = [RidersVC ridersVC];
vc.modalPresentationStyle = UIModalPresentationPopover;
vc.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
UIPopoverPresentationController *popPresenter = [vc popoverPresentationController];
popPresenter.sourceView = vc.view;
popPresenter.barButtonItem= [[UIBarButtonItem alloc] initWithCustomView:button];
popPresenter.backgroundColor = [UIColor colorWithRed:220.0f/255.0f green:227.0f/255.0f blue:237.0f/255.0f alpha:1.0];
[self.parentVC presentViewController:vc animated:YES completion:NULL];

【讨论】:

    【解决方案9】:

    这也对我有用:

    //当前选中单元格的绝对坐标 CGRect frame =[self.view convertRect:[tbvEventsMatch rectForRowAtIndexPath:indexPath] fromView:tbvEventsMatch.viewForBaselineLayout];

    【讨论】:

      【解决方案10】:

      在 Swift 中,在上述答案之间,这对我在任何方向的 iPad 上都有效:

      if let popOverPresentationController : UIPopoverPresentationController = myAlertController.popoverPresentationController {
      
          let cellRect = tableView.rectForRowAtIndexPath(indexPath)
      
          popOverPresentationController.sourceView                = tableView
          popOverPresentationController.sourceRect                = cellRect
          popOverPresentationController.permittedArrowDirections  = UIPopoverArrowDirection.Any
      
      }
      

      【讨论】:

      • 如果你想在 Storyboard 中设置 segue,这很好。您可以从 prepareForSegue: 方法中设置 sourceRect 属性。
      【解决方案11】:

      接受的答案现在无法编译。

      CGRect rect =[tableView rectForRowAtIndexPath:indexPath]; //This is how to get the correct position on the tableView    
      UIPopoverPresentationController *popController = [controller popoverPresentationController];
      popController.sourceRect = rect;
      popController.permittedArrowDirections = 0;  //Here there is no arrow. It is my app's need
      popController.delegate = self;
      popController.sourceView = self.tableView;
      popController.sourceView.backgroundColor = [UIColor yellowColor];
      

      【讨论】:

        猜你喜欢
        • 2019-02-26
        • 2015-02-05
        • 2012-02-05
        • 2013-06-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多