通过包含另一个 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 【问题描述】:我有一个包含 UITextView
的 UIView
子类 (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
认为MyView
是firstResponder
似乎是合理的。但是,由于我在-[MyView becomeFirstResponder]
中依次调用-[UITextView becomeFirstResponder]
,所以两者中的一个必须赢,一个必须输。哪个赢哪个输?如果UITextView
是firstResponder
,那么-[MyView isFirstResponder]
为什么要返回YES
?
有人有什么建议吗?我上面的实现正确吗?
【问题讨论】:
【参考方案1】:虽然我找到了other evidence that people solved this problem the same way。这个实现给我带来了问题。 TLDR:我认为你不应该编写 UIResponder
对象。
我的错误:
-
消费者调用
MyView
的方法,MyView
以编程方式调用-[UITextView becomeFirstResponder]
。从来没有人点击过MyView
的内部UITextView
。
消费者想要关闭键盘。我们可以验证UITextView
是firstResponder
,因为私有API -[UIApplication.sharedApplication.keyWindow firstResponder]
返回UITextView
。
消费者调用[UIApplication sendAction:@selector(resignFirstResponder) to:nil from:nil forEvent:nil]
,但此调用返回NO
。在进行此调用时,UIKit
不会调用 -[UITextView canPerformAction:withSender:]
或 -[UITextView targetForAction:withSender:]
。
但是,如果改为:
-
用户点击
MyView
的UITextView
消费者想要关闭键盘。我们可以验证UITextView
是firstResponder
,因为私有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
对象。
--编辑--
我仍然不确定出了什么问题,但我发现我的应用中有多个 UIWindow
s,而且我从 People That Know™ 那里听说多窗口应用偶尔会出现 firstResponder
问题。
【讨论】:
以上是关于通过包含另一个 firstResponder(一个 UITextView)来创建一个 firstResponder UIView的主要内容,如果未能解决你的问题,请参考以下文章
inputAccessoryView 中的 UITextField 不会成为FirstResponder
将新 UITableView 单元格的 textField 设为 firstResponder
成为FirstResponder 和多个 UITextField 焦点
目标 C:我可以将子视图设置为 firstResponder 吗?