UIMenuController隐藏键盘(UIMenuController hides the ke

2019-08-03 06:58发布

我现在有一个应用程序,它是聊天。 我用的UITextField输入框和气泡用于显示消息时,某些东西如系统SMS。 我想启用的消息气泡(标签)复制粘贴。 问题是,当我想显示UIMenuController,我需要从需求复制到成为第一个响应者的标签。 如果当前正在显示的键盘,当标签成为第一个响应,文本字段会失去焦点,因此,键盘会自动隐藏。 这导致UI滚动,感觉不是很好。 反正是有,我可以保持显示的键盘甚至当我需要显示的菜单吗?

Answer 1:

您可以尝试继承你的UITextField和覆盖firstresponder。 检查你的长按手势处理机如果是的UITextField第一个响应并覆盖nextresponder。



Answer 2:

对于那些谁仍然在寻找答案这里是代码(主要思想是属于neon1,看到链接的问题)。

这个想法是如下:如果响应者不知道如何处理给定的动作,它是propogates在链中的下一个响应者。 到现在为止,我们有两个候选人,第一反应:

  1. 细胞
  2. 文本域

他们每个人都有反应的单独链(其实没有,他们有共同的祖先,所以他们的连锁店有一些共同点,但我们不能使用它):

UITextField <- UIView <- ... <- UIWindow <- UIApplication
UITableViewCell <- UIView <- ... <- UIWindow <- UIApplication

所以,我们想有以下reponders链:

UITextField <- UITableViewCell <- ..... <- UIWindow <- UIApplication

我们需要继承的UITextField(代码摘自这里 ):

CustomResponderTextView.h

@interface CustomResponderTextView : UITextView
@property (nonatomic, weak) UIResponder *overrideNextResponder;
@end

CustomResponderTextView.m

@implementation CustomResponderTextView

@synthesize overrideNextResponder;

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

@end

这段代码很简单:在我们没有设置任何自定义下一个应答的情况下返回真正的响应,否则返回我们的定制响应。

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

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
}

调节器

- (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];
}

最后一步是使(在本例中的文本字段)传播完成第一响应copyMessage:deleteMessage:行动,下一个响应者(在本例中的细胞)。 正如我们所知道的iOS发送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];
}
...

在情况下,我们已经设置了自定义的下一个响应者,我们的一切行动发送给它(你可以修改此部分,如果您需要在文本框的一些动作),否则,我们要求我们的父,如果它能够处理它。



Answer 3:

只是没有在斯威夫特通过尼基塔接过的解决方案。

我有一个聊天屏幕,没有用于文本输入和标签信息(其显示)的文本字段。 当您在消息标签上点击,MENU(复制/粘贴/ ...)应该会出现,但如果已经键盘必须保持开放。

我子类的输入文本字段:

import UIKit

class TxtInputField: UITextField {

weak var overrideNextResponder: UIResponder?

override func nextResponder() -> UIResponder? {
  if overrideNextResponder != nil {
    return overrideNextResponder
  } else {
    return super.nextResponder()
  }
}

override func canPerformAction(action: Selector, withSender sender: AnyObject?) -> Bool {
  if overrideNextResponder != nil {
    return false
  } else {
    return super.canPerformAction(action, withSender: sender)
  }
 }
}

然后在我的自定义邮件标签(的UILabel子类,但它可以是一个视图控制器你的情况),其中有逻辑开始UIMenuController,我后添加

if recognizer.state == UIGestureRecognizerState.Began { ... 

以下块

if let activeTxtField = getMessageThreadInputSMSField() {
  if activeTxtField.isFirstResponder() {
    activeTxtField.overrideNextResponder = self
  } else {
    self.becomeFirstResponder()
  }
} else {
  self.becomeFirstResponder()
}

当用户点击UIMenuController之外

func willHideEditMenu() {
    if let activeTxtField = getMessageThreadInputSMSField() {
      activeTxtField.overrideNextResponder = nil
   }
    NSNotificationCenter.defaultCenter().removeObserver(self, name: UIMenuControllerWillHideMenuNotification, object: nil)
  }

你必须得到的参考activeTxtField对象。 我做到了迭代导航堆栈,让我查看持有所需的文本域控制器,然后使用它。

以防万一你需要它,这里是该部分的代码段为好。

var activeTxtField = CutomTxtInputField()
  for vc in navigationController?.viewControllers {
    if vc is CustomMessageThreadVC {
     let msgVC = vc as! CustomMessageThreadVC         
     activeTxtField = msgVC.textBubble
   }
}


文章来源: UIMenuController hides the keyboard