【问题标题】:How to get the tapped table view cell in custom action in UIMenuController如何在 UIMenuController 的自定义操作中获取点击的表格视图单元格
【发布时间】:2014-01-09 23:19:39
【问题描述】:

我正在尝试使用 UIMenuController 对表格单元格执行自定义操作,UIMenuController 由长按触发。

我在 UITableViewController 子类的 viewDidLoad 方法中注册了 UILongPressGestureRecognizer,并使用 @selector(handleMyAction) 添加了自定义项。

- (void)viewDidLoad
{
    [super viewDidLoad];

    [self.refreshControl addTarget:self action:@selector(refreshView:) forControlEvents:UIControlEventValueChanged];

    UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
    longPressGesture.minimumPressDuration = .5;
    longPressGesture.delegate = self;
    [self.tableView addGestureRecognizer:longPressGesture];
}

-(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
    if(gestureRecognizer.state == UIGestureRecognizerStateBegan)
    {
        CGPoint point = [gestureRecognizer locationInView:self.tableView];
        NSIndexPath * indexPath = [self.tableView indexPathForRowAtPoint:point];
        if(indexPath == nil) return ;
        UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];

        UIMenuItem *it = [[UIMenuItem alloc] initWithTitle:@"My Action on this cell" action:@selector(handleMyAction:)];
        UIMenuController *menu = [UIMenuController sharedMenuController];
        [menu setMenuItems:[NSArray arrayWithObjects:it, nil]];
        [menu setTargetRect:cell.frame inView:cell.superview];
        [menu setMenuVisible:YES animated:YES];
        [self becomeFirstResponder];
    }
}

我也覆盖了

- (BOOL)canBecomeFirstResponder{
    return YES;
}

当我按下一个单元格时,带有自定义条目的上下文菜单会正确显示。但是,问题是如何实现处理自定义操作的方法,这应该在点击的单元格上执行。

- (void)handleMyAction:(id)sender
{
    NSLog(@"Action triggered, however need some way to refer the tapped cell");
}

因为我可以在此方法中获得的唯一信息是发送者,即 UIMenuController 自身,但我不知道如何获取触发菜单的单元格,因此我可以对单元格本身执行进一步操作.

有人可以帮我解决这个问题吗?

谢谢。 海

【问题讨论】:

    标签: ios ios7 uitableview uimenucontroller


    【解决方案1】:

    您目前正在将 UIGestureRecognizer 添加到 tableview 本身。为什么不将其添加到每个单元格中(设置时在 cellForRowAtIndexPath 中)?

    【讨论】:

    • 您的意思是在 cellForRowAtIndexPath 中,对吗?即使我这样做了,菜单也会在单元格上被触发,并且我的动作handleMyAction 的处理程序将被调用,我们在弹出菜单中选择“我在这个单元格上的动作”条目,但是,我如何在handleMyAction 函数中访问单元格,因为这个函数的唯一参数是发送者,它是UIMenuController。
    • 其实如果给cell设置手势识别器,sender就是手势识别器本身,而gestureRecognizer.view就是cell。
    • 起初我长按单元格并触发弹出菜单,无论我在表格视图或表格视图的每个单元格上设置手势识别器,发送者都是识别器,我相信它是是的,如果识别器在单元格上,如您所建议的,recognizer.view 将是单元格。但问题不在这里。当我单击弹出菜单时,我确实需要访问菜单条目的回调函数中的单元格。在这种情况下,回调函数的发送者始终是菜单本身。
    • 好吧,如果您可以访问单元格并为 selectedCell 设置一个 ivar,然后从该函数访问 selectdCell ivar,您无权访问该单元格,但它可以工作......请注意那里可能存在竞争条件。另外,使用 tableview 的 indexPathForSelectedRow 然后 cellForRowAtIndexPath 怎么样?
    • 嗨 valheru,你的意思是我在我的 tableviewcontroller 中创建一个属性并保存我长按的单元格,然后在菜单的回调函数中访问单元格属性:) 是的,这是一个但是,解决方法...对不起,我认为这不是好方法。谢谢。
    【解决方案2】:

    感谢瓦尔赫鲁。我找到了一种“不错”的方法来实现这一点:)

    第一步:在MyTableViewController.m中

    - (void)viewDidLoad
    {
        [super viewDidLoad];
    
        UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
        longPressGesture.minimumPressDuration = .5;
        longPressGesture.delegate = self;
        [self.view addGestureRecognizer:longPressGesture];
    }
    

    在表格视图控制器上注册长按的手势识别器。

    - (BOOL)canBecomeFirstResponder
    {
        return YES;
    }
    

    它允许 MyTableViewController 响应长按并弹出上下文菜单。

    -(void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
    {
        if(gestureRecognizer.state == UIGestureRecognizerStateBegan)
        {
            CGPoint point = [gestureRecognizer locationInView:self.tableView];
            NSIndexPath * indexPath = [self.tableView indexPathForRowAtPoint:point];
            if(indexPath == nil) return ;
    
            MyCell *cell = (MyCell *)[self.tableView cellForRowAtIndexPath:indexPath];
            UIMenuItem *determine = [[UIMenuItem alloc] initWithTitle:@"My Action on this cell" action:@selector(handleMyAction:)];
            UIMenuController *menu = [UIMenuController sharedMenuController];
            [menu setMenuItems:[NSArray arrayWithObjects:determine, nil]];
            [menu setTargetRect:cell.frame inView:cell.superview];
            [menu setMenuVisible:YES animated:YES];
            [cell becomeFirstResponder]; //here set the cell as the responder of the menu action
            cell.delegate = self;// this is optional, if you don't want to implement logic in cell class
        }
    }
    

    当我长按单元格时创建 UIMenuController 和弹出窗口。

    -(void)handleMyAction: (UITableViewCell *)cell
    {
        NSLog(@"%@", cell);
    }
    

    这个函数稍后会从被按下的单元格中调用。

    第二步:创建一个名为 MyCell 的 UITableViewCell 子类

    在 MyCell.h 中,将单元格所属的表格视图控制器定义为单元格的委托。以及菜单项点击时的回调函数

    @property (nonatomic, strong) MyTableViewController *delegate;
    -(void)handleMyAction:(id)sender;
    

    在 MyCell.m 中

    - (BOOL)canBecomeFirstResponder
    {
        return YES;
    }
    
    - (BOOL)canPerformAction:(SEL)action withSender:(id)sender
    {
        if(action == @selector(handleMyAction:))
        {
            return YES;
        }
        return NO;
    }
    

    允许 MyCell 成为第一响应者并通过单击菜单条目来响应 handleMyAction 操作。

    -(void)handleMyAction:(id)sender
    {
        [self.delegate handleMyAction:self]; //it's a coincidence both functions have the same name:)
    }
    

    这是回调函数的定义,点击菜单项时会调用该回调函数,然后调用cell的delegate(MyTableViewController)中的handMyAction函数,这里可以实现cell相关的逻辑。 )

    【讨论】:

      【解决方案3】:

      首先声明一个 NSIndexPath 类型为类变量。

      @property (nonatomic, strong) NSIndexPath *savedIndexPathForThePressedCell;
      

      现在在长按手势识别器功能中,使用识别器视图获取 TableViewCell。现在保存 TableViewCell 的 IndexPath

           - (void)longPressGestureFunction:(UILongPressGestureRecognizer *)recognizer
          {
              UITableViewCell *lTableViewCell = (UITableViewCell *)recognizer.view;
              [lTableViewCell becomeFirstResponder];
      
              /*Save the Indexpath of the cell pressed*/
              self.savedIndexPathForThePressedCell = [mTableView indexPathForCell:lTableViewCell];
      
      if (recognizer.state == UIGestureRecognizerStateBegan)
          {
              UIMenuItem *MenuDelete = [[UIMenuItem alloc] initWithTitle:@"Delete" action:@selector(Delete:)];
              UIMenuItem *MenuForward = [[UIMenuItem alloc] initWithTitle:@"Forward" action:@selector(Forward:)];
              UIMenuItem *MenuAddToContacts = [[UIMenuItem alloc] initWithTitle:@"Add To Contacts" action:@selector(addToContacts:)];
      
              mSharedMenu = [UIMenuController sharedMenuController];
      [mSharedMenu setMenuItems:[NSArray arrayWithObjects: MenuDelete, MenuForward, nil]];
      
              [mSharedMenu setMenuVisible:YES animated:YES];
          }
      

      现在在菜单选择器方法中,根据保存的 indexPath 选择行。

      - (void)Delete:(id)sender {
      //  NSLog(@"\n Delete Selected \n");
      
          [mTableView setEditing:YES animated:YES];
      
          [mTableView selectRowAtIndexPath:self.savedIndexPathForThePressedCell animated:YES scrollPosition:UITableViewScrollPositionNone];
      }
      

      希望对你有帮助!!!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多