Iphone UIMenuController隐藏键盘

Iphone UIMenuController隐藏键盘,iphone,uimenucontroller,iphone-softkeyboard,Iphone,Uimenucontroller,Iphone Softkeyboard,我目前有一个聊天的应用程序。 我使用UItextField作为输入框,使用气泡作为显示消息,比如系统短信。 我想在消息气泡(标签)上启用复制粘贴。问题是,当我想显示UIMenuController时,我需要从中复制的标签需要成为第一响应者。如果当前显示键盘,当标签成为第一响应者时,文本字段将失去焦点,因此键盘将自动隐藏。 这会导致UI滚动,感觉不好。 即使在需要显示菜单时,是否仍可以保持键盘显示 您可以尝试对uitextfield进行子类化,并覆盖firstresponder。如果uitext

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


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

对于仍在这里寻找答案的人,请使用代码(主要思想属于neon1,请参阅链接问题)

其思想如下:如果响应者不知道如何处理给定的操作,它会将其转发给链中的下一个响应者。到目前为止,我们有两名急救员候选人:

  • 细胞
  • 文本字段
  • 他们每个人都有单独的响应者链(事实上,不,他们有共同的祖先,所以他们的链有共同点,但我们不能使用它):

    customresponderextview.m

    @implementation CustomResponderTextView
    
    @synthesize overrideNextResponder;
    
    - (UIResponder *)nextResponder {
        if (overrideNextResponder != nil)
            return overrideNextResponder;
        else
            return [super nextResponder];
    }
    
    @end
    
    @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
    }
    
    ...
    - (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
        if (overrideNextResponder != nil)
            return NO;
        else
            return [super canPerformAction:action withSender:sender];
    }
    ...
    
    这段代码非常简单:如果我们没有设置任何自定义下一个响应程序,它将返回真正的响应程序,否则将返回自定义响应程序

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

    CustomCell.m

    @implementation CustomResponderTextView
    
    @synthesize overrideNextResponder;
    
    - (UIResponder *)nextResponder {
        if (overrideNextResponder != nil)
            return overrideNextResponder;
        else
            return [super nextResponder];
    }
    
    @end
    
    @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
    }
    
    ...
    - (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
        if (overrideNextResponder != nil)
            return NO;
        else
            return [super canPerformAction:action withSender:sender];
    }
    ...
    
    控制器

    - (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发送
    canperformation:with sender:
    以了解,如果给定响应者可以处理该操作

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

    customresponderextview.m

    @implementation CustomResponderTextView
    
    @synthesize overrideNextResponder;
    
    - (UIResponder *)nextResponder {
        if (overrideNextResponder != nil)
            return overrideNextResponder;
        else
            return [super nextResponder];
    }
    
    @end
    
    @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
    }
    
    ...
    - (BOOL)canPerformAction:(SEL)action withSender:(id)sender {
        if (overrideNextResponder != nil)
            return NO;
        else
            return [super canPerformAction:action withSender:sender];
    }
    ...
    
    如果我们已经设置了自定义的下一个响应程序,我们会将所有操作发送给它(如果您需要textField上的一些操作,您可以修改此部分),否则我们会询问我们的超类型是否可以处理它。

    通过Nikita Take的解决方案在Swift上完成了

    我有一个聊天屏幕,其中有一个用于文本输入的文本字段和用于消息(其显示)的标签。当您点击消息标签时,应显示菜单(复制/粘贴/…),但键盘必须保持打开状态(如果已经打开)

    我对输入文本字段进行了子分类:

    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
       }
    }
    

    似乎同样的问题是。。。1.2.否,当我使用长prees手势(当键盘处于活动状态时)选择单元格时,UImenucontroller会出现,但键盘会消失。我希望键盘在屏幕上。当长按显示菜单时,您必须编写类似于[sender.view becomeFirstResponder]的代码;要保持键盘状态。这对我来说不是闹着玩的,当UIMenuController启动时,键盘正在消失。长按手势一行类似的东西:
    @interface inputExtField:UITextField@property(非原子,弱)UIResponder*inputNextResponder@end@implementation InputExtField@Synthesis inputNextResponder;-(UIResponder*)nextResponder{if(inputNextResponder!=nil)返回inputNextResponder;else返回[super nextResponder];}@end
    格式有点混乱:(但我想你会明白我的意思。如果有助于解决你的问题,请接受我的回答。HTH。不,在这种情况下没有帮助。你能告诉我你到底实现了什么吗?类TIField:UIExtView{弱变量overrideNextResponder:UIResponder?override var next:UIResponder?{获取{if overrideNextResponder!=nil{return overrideNextResponder}else{return super.next}}}override func canperformation(uu动作:选择器,带sender sender:Any?->Bool{if overrideNextResponder!=nil{return false}else{return super.canperformation(action,with sender:sender)}}@尼基塔:谢谢你的帖子。但我的情况仍然不起作用,你能帮我解决这个问题吗。@尼基塔:谢谢你的帖子。但我的情况仍然不起作用,你能帮我解决这个问题吗?谢谢你的帖子。我的情况仍然不起作用,你能帮我解决这个问题吗?你能分享演示吗