通过包含另一个firstResponder(一个UITextView)来创建一个firstResponse r UIVi



我有一个包含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

然而,当我阅读苹果的Event Delivery:The Responder Chain文档时,我认为这可能是一个不正确的实现。我找不到任何关于如何用另一个UIResponder创建UIResponder的文档或帖子。

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

有人有什么建议吗?我的上述实施是否正确?

尽管我发现了其他证据表明人们以同样的方式解决了这个问题。这个实现给我带来了问题。TLDR:我认为您不应该编写UIResponder对象。

我的错误:

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

但是,如果改为:

  1. 用户点击MyViewUITextView
  2. 消费者想要丢弃键盘。我们可以验证UITextViewfirstResponder,因为私有API -[UIApplication.sharedApplication.keyWindow firstResponder]返回UITextView
  3. 一个使用者调用[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对象。

--编辑--

我仍然不确定出了什么问题,但我发现我的应用程序中有多个UIWindow,我收到了知情人士的来信™多窗口应用程序可能偶尔会出现CCD_ 56问题。

最新更新