通过包含另一个 firstResponder(一个 UITextView)来创建一个 firstResponder UIView

Posted

技术标签:

【中文标题】通过包含另一个 firstResponder(一个 UITextView)来创建一个 firstResponder UIView【英文标题】:Make a firstResponder UIView by containing another firstResponder (a UITextView) 【发布时间】:2016-07-19 17:55:27 【问题描述】:

我有一个包含 UITextViewUIView 子类 (MyView)。我希望MyView 对所有UIResponder 方法使用UITextView,如下所示:

@implementation MyView

- (BOOL)canBecomeFirstResponder 
  return _textView.canBecomeFirstResponder

- (BOOL)becomeFirstResponder 
  return [_textView becomeFirstResponder];

- (BOOL)canResignFirstResponder 
  return [_textView canResignFirstResponder];

- (BOOL)resignFirstResponder 
  // UIResponder documentation says [super resignFirstResponder]
  // must be called somewhere in this method
  BOOL superResignedFirstResponder = [super resignFirstResponder];
  if (superResignedFirstResponder) 
    return [_textView resignFirstResponder];
   else 
    return NO;
  

- (BOOL)isFirstResponder 
  return [_textView isFirstResponder];


@end

但是,当我阅读Apple's Event Delivery: The Responder Chain documentation 时,我认为这可能是一个不正确的实现。我找不到任何有关如何创建 UIResponder 和另一个 UIResponder 的文档或帖子。

UIKit 的概念正好是 1 个firstResponder,所以当MyView 处理-becomeFirstResponder 并返回YES 时,UIKit 认为MyViewfirstResponder 似乎是合理的。但是,由于我在-[MyView becomeFirstResponder] 中依次调用-[UITextView becomeFirstResponder],所以两者中的一个必须赢,一个必须输。哪个赢哪个输?如果UITextViewfirstResponder,那么-[MyView isFirstResponder] 为什么要返回YES

有人有什么建议吗?我上面的实现正确吗?

【问题讨论】:

【参考方案1】:

虽然我找到了other evidence that people solved this problem the same way。这个实现给我带来了问题。 TLDR:我认为你不应该编写 UIResponder 对象。

我的错误:

    消费者调用MyView 的方法,MyView 以编程方式调用-[UITextView becomeFirstResponder]。从来没有人点击过MyView 的内部UITextView。 消费者想要关闭键盘。我们可以验证UITextViewfirstResponder,因为私有API -[UIApplication.sharedApplication.keyWindow firstResponder] 返回UITextView。 消费者调用[UIApplication sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil],但此调用返回NO。在进行此调用时,UIKit 不会调用 -[UITextView canPerformAction:withSender:]-[UITextView targetForAction:withSender:]

但是,如果改为:

    用户点击MyViewUITextView 消费者想要关闭键盘。我们可以验证UITextViewfirstResponder,因为私有API -[UIApplication.sharedApplication.keyWindow firstResponder] 返回UITextView。 消费者调用[UIApplication sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil],现在这个调用返回YES。在进行此调用时,UIKit 会按预期调用-[UITextView canPerformAction:withSender:]-[UITextView targetForAction:withSender:],然后当然会调用-[UITextView resignFirstResponder],这会成功。

我不知道为什么在第一种情况下[UIApplication sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil] 没有正确委托给UITextView,但我必须假设因为-[MyView becomeFirstResponder] 没有像文档所说的那样委托给[super becomeFirstResponder],所以有些事情搞砸了.我认为您不应该编写 UIResponder 对象。

--编辑--

我仍然不确定出了什么问题,但我发现我的应用中有多个 UIWindows,而且我从 People That Know™ 那里听说多窗口应用偶尔会出现 firstResponder问题。

【讨论】:

以上是关于通过包含另一个 firstResponder(一个 UITextView)来创建一个 firstResponder UIView的主要内容,如果未能解决你的问题,请参考以下文章

inputAccessoryView 中的 UITextField 不会成为FirstResponder

将新 UITableView 单元格的 textField 设为 firstResponder

成为FirstResponder 和多个 UITextField 焦点

目标 C:我可以将子视图设置为 firstResponder 吗?

uiresponder 下一个文本字段在 keyEvent 之后成为FirstResponder

当 UITextField 成为FirstResponder 时得到通知