【发布时间】:2011-12-20 17:24:28
【问题描述】:
使用通知中心,如How can I get a textDidChange (like for a UISearchBar) method for a UITextField? 中所述,允许您在 iOS UITextField 中的文本更改时收到通知。我没有看到类似的选择更改通知。检测和响应 UITextField 选择变化的最佳方法是什么?
【问题讨论】:
标签: iphone ios ipad uitextfield
使用通知中心,如How can I get a textDidChange (like for a UISearchBar) method for a UITextField? 中所述,允许您在 iOS UITextField 中的文本更改时收到通知。我没有看到类似的选择更改通知。检测和响应 UITextField 选择变化的最佳方法是什么?
【问题讨论】:
标签: iphone ios ipad uitextfield
这个link 有一个解决方案,不会弄乱私有 api:
简而言之:子类UITextField,实现
-(BOOL)canPerformAction:(SEL)action withSender:(id)sender
并检查选择范围是否已更改。但这不会通知水龙头。
所以我所做的是在子类化之后,观察selectedTextRange 属性:
-(void)awakeFromNib {
[self addObserver:self forKeyPath:@"selectedTextRange" options:0 context:nil];
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
[self notifyDelegateIfNecessary];
}
在 iOS8 中运行良好。
【讨论】:
有一种简单的方法可以检测 textField 中的选择
在 viewDidAppear 中添加对象属性观察器
[self.keyboardInputFieldPassword addObserver:self forKeyPath:@"selectedTextRange" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
然后为属性添加观察功能
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if([keyPath isEqualToString:@"selectedTextRange"] && self.keyboardInputFieldPassword == object)
[self textFieldDidChangeSelection:self.keyboardInputFieldPassword];
}
这将捕获 UITextField 中的选择范围
为了遵守约定,你应该在 viewDidDisappear 中删除Observer
[self.keyboardInputFieldPassword removeObserver:self forKeyPath:@"selectedTextRange" context:nil];
【讨论】:
斯威夫特 4
private func listenForSelection(in textField:UITextField) {
textField.addObserver(self, forKeyPath: "selectedTextRange", options: [.new,.old], context: nil)
}
private func unlistenForSelection(in textField:UITextField) {
textField.removeObserver(self, forKeyPath: "selectedTextRange")
}
override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
let textField = object as? UITextField
assert(keyPath == "selectedTextRange")
assert(textField != nil)
// select everything but the first and last characters - just and example of the UITextInput API if you want to modify the selection
if let startPosition = textField.position(from: textField.beginningOfDocument, offset: 1),
let endPosition = textField.position(from: textField.endOfDocument, offset: -1) {
let selectionRange = textField.textRange(from: startPosition, to: endPosition)
textField.selectedTextRange = selectionRange
}
}
【讨论】:
将使用目标/操作的方法连接到UITextField 实例上的UIControlEventEditingChanged 控制事件。这可以在界面构建器或代码中通过将目标/操作对添加到文本字段然后实现指定的方法来完成。
[self.textField addTarget:self action:@selector(textFieldTextChanged:) forControlEvents:UIControlEventEditingChanged];
UITextField 还声明了一个UITextFieldDelegate 协议,其中包含您可以在类中实现的方法,以便在UITextField 实例的更改时收到通知。我建议您熟悉委托,因为它是 Cocoa 框架中的常见模式。
【讨论】:
UIControlEventEditingChanged 仅指文本编辑。即,仅当文本更改而文本字段 isEditing 时才会触发该操作。这不包括选择更改。