UIMenuController隐藏了键盘

Anu*_*bra 6 iphone uimenucontroller iphone-softkeyboard

我目前有一个用于聊天的应用程序.我使用UItextField作为输入框和气泡来显示消息,有些东西就像系统短信.我想在消息气泡(标签)上启用复制粘贴.问题是,当我想显示UIMenuController时,我需要复制的标签需要成为第一响应者.如果当前显示键盘,当标签成为第一响应者时,文本字段将失去焦点,因此键盘将自动隐藏.这导致UI滚动并感觉不好.无论如何,即使我需要显示菜单,我仍然可以保持键盘显示?

在此输入图像描述

在此输入图像描述

Nik*_*ook 11

对于那些仍然在这里寻找答案的人是代码(主要想法属于neon1,请参阅链接问题).

这个想法如下:如果响应者不知道如何处理给定的动作,它会将其传播给链中的下一个响应者.到目前为止,我们有两名第一响应者候选人:

  1. 细胞
  2. 文本域

他们每个人都有独立的响应者链(事实上,不,他们确实有共同的祖先,因此他们的链有一些共同点,但我们不能使用它):

UITextField <- UIView <- ... <- UIWindow <- UIApplication
UITableViewCell <- UIView <- ... <- UIWindow <- UIApplication
Run Code Online (Sandbox Code Playgroud)

所以我们希望有以下的转发链:

UITextField <- UITableViewCell <- ..... <- UIWindow <- UIApplication
Run Code Online (Sandbox Code Playgroud)

我们需要子类UITextField(代码取自这里):

CustomResponderTextView.h

@interface CustomResponderTextView : UITextView
@property (nonatomic, weak) UIResponder *overrideNextResponder;
@end
Run Code Online (Sandbox Code Playgroud)

CustomResponderTextView.m

@implementation CustomResponderTextView

@synthesize overrideNextResponder;

- (UIResponder *)nextResponder {
    if (overrideNextResponder != nil)
        return overrideNextResponder;
    else
        return [super nextResponder];
}

@end
Run Code Online (Sandbox Code Playgroud)

这段代码非常简单:如果我们没有设置任何自定义的下一个响应者,它会返回真实的响应者,否则返回我们的自定义响应者.

现在我们可以在代码中设置新的响应者(我的示例添加自定义操作):

CustomCell.m

@implementation CustomCell
- (BOOL) canBecomeFirstResponder {
    return YES;
}

- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
    return (action == @selector(copyMessage:) || action == @selector(deleteMessage:));
}
@end

- (void) copyMessage:(id)sender {
   // copy logic here
}

- (void) deleteMessage:(id)sender {
   // delete logic here
}
Run Code Online (Sandbox Code Playgroud)

调节器

- (void) viewDidLoad {
    ...
    UIMenuItem *copyItem = [[UIMenuItem alloc] initWithTitle:@"Custom copy" action:@selector(copyMessage:)];
    UIMenuItem *deleteItem = [[UIMenuItem alloc] initWithTitle:@"Custom delete" action:@selector(deleteMessage:)];
    UIMenuController *menu = [UIMenuController sharedMenuController];
    [menu setMenuItems:@[copyItem, deleteItem]];
    ...
}

- (void) longCellTap {
    // cell is UITableViewCell, that has received tap
    if ([self.textField isFirstResponder]) {
        self.messageTextView.overrideNextResponder = cell;
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(menuDidHide:) name:UIMenuControllerDidHideMenuNotification object:nil];
    } else {
        [cell becomeFirstResponder];
    }
}

- (void)menuDidHide:(NSNotification*)notification {
    self.messageTextView.overrideNextResponder = nil;
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIMenuControllerDidHideMenuNotification object:nil];
}
Run Code Online (Sandbox Code Playgroud)

最后一步是使第一响应者(在本例中的文本字段)传播完成copyMessage:deleteMessage:行动,下一个响应者(在本例中的细胞).正如我们所知,iO发送canPerformAction:withSender:知道,如果给予响应者可以处理该动作.

我们需要修改CustomResponderTextView.m并添加以下功能:

CustomResponderTextView.m

...
- (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
    if (overrideNextResponder != nil)
        return NO;
    else
        return [super canPerformAction:action withSender:sender];
}
...
Run Code Online (Sandbox Code Playgroud)

如果我们设置了我们的自定义下一个响应者,我们会向它发送所有操作(如果你需要在textField上执行某些操作,你可以修改这个部分),否则我们会问我们的超类型是否可以处理它.


akd*_*uza 2

您可以尝试对 uitextfield 进行子类化并覆盖第一个响应程序。如果 uitextfield 是第一个响应者,请检查长按手势处理程序并覆盖下一个响应者。

  • 类似的东西:`@interface InputTextField : UITextField @property (nonatomic,weak) UIResponder *inputNextResponder; @end @implementation InputTextField @synthesize inputNextResponder; - (UIResponder *)nextResponder { if (inputNextResponder != nil) return inputNextResponder; 否则返回[超级nextResponder];} @end` 格式有点乱:(但我想你会明白的。如果可以帮助你解决你的问题,请接受我的答案。HTH。 (2认同)