如何在 UIMenuController 的自定义操作中获取点击的表格视图单元格
Posted
技术标签:
【中文标题】如何在 UIMenuController 的自定义操作中获取点击的表格视图单元格【英文标题】:How to get the tapped table view cell in custom action in 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 自身,但我不知道如何获取触发菜单的单元格,因此我可以对单元格本身执行进一步操作.
有人可以帮我解决这个问题吗?
谢谢。 海
【问题讨论】:
【参考方案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];
希望对你有帮助!!!
【讨论】:
以上是关于如何在 UIMenuController 的自定义操作中获取点击的表格视图单元格的主要内容,如果未能解决你的问题,请参考以下文章
UIMenuController sharedMenuController - uicollectionview 的自定义菜单项不在 ios 7 中显示