显示 UIMenuController 取消选择 UITableViewCell

Posted

技术标签:

【中文标题】显示 UIMenuController 取消选择 UITableViewCell【英文标题】:Showing UIMenuController deselects UITableViewCell 【发布时间】:2013-01-22 15:06:00 【问题描述】:

我在显示UIMenuController 的表格视图单元格上实现了长按手势识别器。但是当菜单显示时,相应的表格视图单元格会取消选择。在显示菜单之前,我会根据需要拨打[self becomeFirstResponder]。我认为这个调用会取消选择单元格,但是如何使它在 UIMenuController 可见时保持选中状态?

【问题讨论】:

【参考方案1】:

根据the documentation,在您的UITableViewDelegate 中,当您不想取消选择行时,覆盖tableView:willDeselectRowAtIndexPath: 并返回nil

【讨论】:

【参考方案2】:

实现这一点的更简单方法是使用特定的 UITableViewDelegate 方法来处理 UIMenuController。 但首先,要使单元格保持选中状态,请将呈现菜单的单元格的值存储在您的类中:

NSIndexPath                     *_editingIndexPath;

然后实现 UITableViewDelegateMethods:

- (BOOL)tableView:(UITableView *)tableView shouldShowMenuForRowAtIndexPath:(NSIndexPath *)indexPath

    MyCustomTableViewCell *cell = (MyCustomTableViewCell *) [_tableView cellForRowAtIndexPath:indexPath];
    _editingIndexPath = indexPath;
    cell.showingMenu = YES;

    return YES;


- (BOOL)tableView:(UITableView *)tableView canPerformAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender

    if (action == @selector(copy:)) 
        return YES;
    

    return NO;



- (void)tableView:(UITableView *)tableView performAction:(SEL)action forRowAtIndexPath:(NSIndexPath *)indexPath withSender:(id)sender

    if (action == @selector(copy:))
    
        UITableViewCell *cell = [self tableView:tableView cellForRowAtIndexPath:indexPath];
        if (cell && [cell isKindOfClass:[MessageConversationCell class]])
        
            [UIPasteboard generalPasteboard].string = cell.textLabel.text;
        
    

上面的代码将负责在长按后在单元格上显示“复制”菜单。 现在,如果您希望在显示菜单时单元格保持选中状态:

在名为“showingMenu”的自定义单元格中添加一个@property(请注意,此属性已在此答案的第一个代码块中设置)。

@property (nonatomic, assign) BOOL showingMenu;

将以下方法添加(或修改,如果已经存在)到您的自定义单元格。这将负责在菜单尝试取消突出显示后保持单元格突出显示(您可以实现自己的逻辑来突出显示单元格,在这种情况下将其放在 if 条件的第一个分支中):

- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated


    if (_showingMenu)
    
        [super setHighlighted:YES]
    
    else
    
        [super setHighlighted:highlighted];
    

添加一个观察者,以便在菜单将要显示时得到通知。这进入视图控制器,而不是自定义单元格:

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didShowEditMenu:) name:UIMenuControllerDidShowMenuNotification object:nil];

在视图控制器上添加菜单显示时要调用的方法:

- (void)didShowEditMenu:(NSNotification *)not 
    [_tableView selectRowAtIndexPath:_editingIndexPath animated:NO scrollPosition:UITableViewScrollPositionNone];
    MyCustomTableViewCell *cell = (MyCustomTableViewCell*)[_conversationTableView cellForRowAtIndexPath:_editingIndexPath];
    cell.showingMenu = NO;

并且不要忘记在不再需要时移除观察者:

[[NSNotificationCenter defaultCenter] removeObserver:self name:UIMenuControllerDidShowMenuNotification object:nil];

这将在长按单元格时显示一个菜单,并保持该单元格处于选中状态,直到菜单消失,因为选择了一个选项或因为用户点击了其他地方。当您选择消息时,它的工作方式与 Whatsapp 的工作方式非常相似。

【讨论】:

【参考方案3】:

您说您正在调用[self becomeFirstResponder],但您的问题并未表明 self 是哪个对象。我猜self 是你的控制器。您应该将becomeFirstResponder 消息发送到生成 UIMenuController 的 UITableViewCell。

- (void)longPress:(UILongPressGestureRecognizer *)recognizer 
 
    if (recognizer.state == UIGestureRecognizerStateBegan) 
        
        TSTableViewCell *cell = (TSTableViewCell *)recognizer.view;

        //This is your problem
        [cell becomeFirstResponder]; 

        UIMenuItem *flag = [[UIMenuItem alloc] initWithTitle:@"Flag" action:@selector(flag:)];    
        UIMenuItem *approve = [[UIMenuItem alloc] initWithTitle:@"Approve" action:@selector(approve:)]; 
        UIMenuItem *deny = [[UIMenuItem alloc] initWithTitle:@"Deny" action:@selector(deny:)];

        UIMenuController *menu = [UIMenuController sharedMenuController];    
        [menu setMenuItems:[NSArray arrayWithObjects:flag, approve, deny, nil]];    
        [menu setTargetRect:cell.frame inView:cell.superview];    
        [menu setMenuVisible:YES animated:YES];    
    

【讨论】:

【参考方案4】:

我找到了这个解决方案:

- (void)handleLongPress:(UILongPressGestureRecognizer *)longPressRecognizer

    if (longPressRecognizer.state == UIGestureRecognizerStateBegan) 

        UITableViewCell *cell = (UITableViewCell *)longPressRecognizer.view;

        [cell setSelected:YES];

        ...        
    
         

【讨论】:

以上是关于显示 UIMenuController 取消选择 UITableViewCell的主要内容,如果未能解决你的问题,请参考以下文章

确定何时解除 UIMenuController?

使用按钮单击显示 UIMenuController

显示 UIMenuController 时获取选定的文本

更改视图控制器后 UIMenuController 不显示

使用自定义 UIMenuController 项从 UIPasteboard 中复制和检索值

UIMenuController:如何判断哪个 menuItem 被按下?