今天我们来讨论一个小细节,我们常常会遇见这样的需求,一个按钮根据所有的输入框是否为空来显示灰色或者高亮。如下图所示:
textField的代理中判断,当所有输入框的长度大于0的时候,按钮就高亮。但是实施起来的时候有点小问题,当我们点击地址簿,选择地址回来以后并没有触发textField的代理。这是为什么呢?
textField.addTarget(self, action: #selector(valueChange), for: .allEvents)
textView.delegate = self
@objc func valueChange() {
print("----textField系统的方法")
}
func textViewDidChange(_ textView: UITextView){
print("----textView系统的方法")
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
textField.text = "8d8dc8d78d3bcf7caef7c5a8d7d2484b486f"
textView.text = "描述"
}
这是系统的方法,当我们点击view的时候textFiled和TextView都赋上了值,但是都没有触发代理方法。
让我们看一下,RxSwift封装的是否触发:
textField.rx.text.orEmpty.skip(1).subscribe(onNext: { (text) in
print("textField:", text)
}).disposed(by: disposebag)
textView.rx.text.orEmpty.skip(1).subscribe(onNext: { (text) in
print("textView:", text)
}).disposed(by: disposebag)
打印
textView: 描述
我们发现TextFiled没有触发,TextView触发了,这是为什么吗?让我们一起走进源码
TextFiled:
/// This is a separate method to better communicate to public consumers that
/// an `editingEvent` needs to fire for control property to be updated.
internal func 'controlPropertyWithDefaultEvents'<T>(
editingEvents: UIControl.Event = [.allEditingEvents, .valueChanged],
getter: @escaping (Base) -> T,
setter: @escaping (Base, T) -> Void
) -> ControlProperty<T> {
return controlProperty(
editingEvents: editingEvents,
getter: getter,
setter: setter
)
}
由代码可知,
RxSwift中TextFiled封装的是系统的Event,所以系统没触发,他也不会触发。
再看看为什么RxSwift中TextView可以触发
/// Reactive wrapper for `text` property.
public var value: ControlProperty<String?> {
let source: Observable<String?> = Observable.deferred { [weak textView = self.base] in
let text = textView?.text
let textChanged = textView?.textStorage
// This project uses text 'storage notifications' because
// that’s the only way to catch autocorrect changes
// in all cases. Other suggestions are welcome.
.rx.'didProcessEditingRangeChangeInLength'
// This observe on is here because text storage
// will emit event while process is not completely done,
// so rebinding a value will cause an exception to be thrown.
.observeOn(MainScheduler.asyncInstance)
.map { _ in
return textView?.textStorage.string
}
?? Observable.empty()
return textChanged
.startWith(text)
}
我们看见了
RxSwift封装的是通知,所以会打印
那我们应该如何解决呢,其实方法很简单,只要在赋值的地方加一句代码就OK了,重新触发一下
// send all actions associated with events
textField.sendActions(for: .allEvents)