我有一个带有一些NSTextFields的Mac应用程序(SDK 10.10):
由于我需要在文本字段获取并重新调整焦点时收到通知,因此我将NSTextField子类化:
@interface MyTextField : NSTextField
@end
@implementation MyTextField
- (BOOL)becomeFirstResponder
{
BOOL didBecomeFirstResponder = [super becomeFirstResponder];
NSLog(@"%@ didBecomeFirstResponder = %@", [self accessibilityLabel], didBecomeFirstResponder?@"YES":@"NO");
return didBecomeFirstResponder;
}
- (BOOL)resignFirstResponder
{
BOOL didResignFirstResponder = [super resignFirstResponder];
NSLog(@"%@ didResignFirstResponder = %@", [self accessibilityLabel], didResignFirstResponder?@"YES":@"NO");
return didResignFirstResponder;
}
@end
在运行此代码并在3个文本字段之间进行选项卡时,我在控制台中获得此输出:
firstField didResignFirstResponder = YES
firstField didBecomeFirstResponder = YES
secondField didResignFirstResponder = YES
secondField didBecomeFirstResponder = YES
thirdField didResignFirstResponder = YES
thirdField didBecomeFirstResponder = YES
firstField didResignFirstResponder = YES
firstField didBecomeFirstResponder = YES
secondField didResignFirstResponder = YES
secondField didBecomeFirstResponder = YES
每次按TAB键(或单击其中一个非活动文本字段),应用程序输出
<new first responder> didResignFirstResponder = YES
<new first responder> didBecomeFirstResponder = YES
不应该
<old first responder> didResignFirstResponder = YES
<new first responder> didBecomeFirstResponder = YES
???
这里有什么特别错的吗?
- (BOOL)resignFirstResponder
的文档说
通知接收方已被要求放弃其状态 第一响应者在其窗口。
那么为什么要在新的第一响应者而不是旧响应者上调用resignFirstResponder
?
答案 0 :(得分:1)
我遇到了同样的问题但无法找到解决方案,因此我最终解决了这个问题并使用textDidEndEditing()
方法达到了同样的目的。 Swift代码:
MyTextField
子类NSTextField
并向其添加myDelegate
属性,该属性应在文本字段失去焦点后处理逻辑。
class MyTextField : NSTextField
{
/// Custom delegate with other methods than NSTextFieldDelegate.
var myDelegate: MyTextFieldDelegate? = nil;
override func becomeFirstResponder() -> Bool {
let became = super.becomeFirstResponder();
if (became) {
self.myDelegate?.myTextFieldDidBecomeFirstResponder(self);
}
return became;
}
override func resignFirstResponder() -> Bool {
let resigned = super.resignFirstResponder();
if (resigned) {
self.myDelegate?.myTextFieldDidResignFirstResponder(self);
}
return resigned;
}
override func textDidEndEditing(obj: NSNotification) {
super.textDidEndEditing(obj);
self.myDelegate?.myTextFieldDidResignFirstResponder(self);
}
}
协议本身:
protocol MyTextFieldDelegate
{
func myTextFieldDidBecomeFirstResponder(textField: MyTextField);
func myTextFieldDidResignFirstResponder(textField: MyTextField);
}
显然,不是使用和调用委托,而是可以在那里实现丢失/获得的焦点逻辑(例如绘制不同的边界等)。
线索是textDidEndEditing()
方法,当我点击另一个字段,当我按回车键或当我退出时,它似乎工作正常。
答案 1 :(得分:1)
Apple开发者论坛上的某人解释了其行为的原因:
当文本字段具有焦点时,它们实际上并不是第一响应者。 Cocoa创建一个特殊的文本视图,称为field editor,并将其临时添加到视图层次结构中,覆盖文本字段。它使该文本视图成为第一响应者。此文本视图负责处理所有用户交互。
来源:https://forums.developer.apple.com/thread/109158#339676
IMO是最好的解决方案,重写textDidEndEditing:
方法(由Michał在this answer中提及)。
如果您不想继承UITableViewCell
的子类,请创建一个符合NSTextFieldDelegate
协议并实现controlTextDidEndEditing:
方法的类。然后,设置您的NSTextField
实例的delegate
属性。
最后,您可以覆盖NSTextField
子类的fieldEditor:forObject:
方法。但是实际上没有这种方法的正式文档(我可以找到)。
要了解有关“字段编辑器”的更多信息,请阅读以下文章: