-
UILabel
-
UITextField糜颠、UITextView
// .orEmpty 可以將 String? 類型的 ControlProperty 轉(zhuǎn)成 String,省得我們?cè)偃ソ獍?textField.rx.text.orEmpty.asObservable()
.subscribe(onNext: {
print("您輸入的是:\($0)")
})
.disposed(by: disposeBag)
// 當(dāng)然我們直接使用 change 事件效果也是一樣的
textField.rx.text.orEmpty.changed
.subscribe(onNext: {
print("您輸入的是:\($0)")
})
.disposed(by: disposeBag)
將內(nèi)容綁定到其他控件上
Throttling 的作用:
Throttling 是 RxSwift 的一個(gè)特性。因?yàn)橛袝r(shí)當(dāng)一些東西改變時(shí),通常會(huì)做大量的邏輯操作。而使用 Throttling 特性,不會(huì)產(chǎn)生大量的邏輯操作宫屠,而是以一個(gè)小的合理的幅度去執(zhí)行。比如做一些實(shí)時(shí)搜索功能時(shí)滑蚯,這個(gè)特性很有用浪蹂。
//當(dāng)文本框內(nèi)容改變
let input = inputField.rx.text.orEmpty.asDriver() // 將普通序列轉(zhuǎn)換為 Driver
.throttle(0.3) //在主線程中操作,0.3秒內(nèi)值若多次改變告材,取最后一次
//內(nèi)容綁定到另一個(gè)輸入框中
input.drive(outputField.rx.text)
.disposed(by: disposeBag)
//內(nèi)容綁定到文本標(biāo)簽中
input.map{ "當(dāng)前字?jǐn)?shù):\($0.count)" }
.drive(label.rx.text)
.disposed(by: disposeBag)
//根據(jù)內(nèi)容字?jǐn)?shù)決定按鈕是否可用
input.map{ $0.count > 5 }
.drive(button.rx.isEnabled)
.disposed(by: disposeBag)
同時(shí)監(jiān)聽多個(gè) textField 內(nèi)容的變化(textView 同理)
let observable = Observable.combineLatest(inputField.rx.text.orEmpty, outputField.rx.text.orEmpty) { (inputText, outputText) -> (String, String) in
return (inputText, outputText)
}
observable.map { $0.0 + "*****" + $0.1 }
.bind(to: label.rx.text)
.disposed(by: disposeBag)
observable.map { $0.0.count > 5 && $0.1.count > 5 }
.bind(to: button.rx.isEnabled)
.disposed(by: disposeBag)
事件監(jiān)聽
通過(guò) rx.controlEvent 可以監(jiān)聽輸入框的各種事件坤次,且多個(gè)事件狀態(tài)可以自由組合。除了各種 UI 控件都有的 touch 事件外斥赋,輸入框還有如下幾個(gè)獨(dú)有的事件:
- editingDidBegin:開始編輯(開始輸入內(nèi)容)
- editingChanged:輸入內(nèi)容發(fā)生改變
- editingDidEnd:結(jié)束編輯
- editingDidEndOnExit:按下 return 鍵結(jié)束編輯
- allEditingEvents:包含前面的所有編輯相關(guān)事件
textField.rx.controlEvent([.editingDidBegin]) //狀態(tài)可以組合
.asObservable()
.subscribe(onNext: { _ in
print("開始編輯內(nèi)容!")
}).disposed(by: disposeBag)
UITextView 獨(dú)有的方法
UITextView 還封裝了如下幾個(gè)委托回調(diào)方法:
- didBeginEditing:開始編輯
- didEndEditing:結(jié)束編輯
- didChange:編輯內(nèi)容發(fā)生改變
- didChangeSelection:選中部分發(fā)生變化
//開始編輯響應(yīng)
textView.rx.didBeginEditing
.subscribe(onNext: {
print("開始編輯")
})
.disposed(by: disposeBag)
//結(jié)束編輯響應(yīng)
textView.rx.didEndEditing
.subscribe(onNext: {
print("結(jié)束編輯")
})
.disposed(by: disposeBag)
//內(nèi)容發(fā)生變化響應(yīng)
textView.rx.didChange
.subscribe(onNext: {
print("內(nèi)容發(fā)生改變")
})
.disposed(by: disposeBag)
//選中部分變化響應(yīng)
textView.rx.didChangeSelection
.subscribe(onNext: {
print("選中部分發(fā)生變化")
})
.disposed(by: disposeBag)
-
UIButton缰猴、UIBarButtonItem
按鈕點(diǎn)擊響應(yīng)
button.rx.tap
.subscribe(onNext: { [weak self] in
self?.showMessage("按鈕被點(diǎn)擊")
})
.disposed(by: disposeBag)
// 或者這樣寫
button.rx.tap
.bind { [weak self] in
self?.showMessage("按鈕被點(diǎn)擊")
}
.disposed(by: disposeBag)
按鈕標(biāo)題(title)的綁定
//創(chuàng)建一個(gè)計(jì)時(shí)器(每1秒發(fā)送一個(gè)索引數(shù))
let timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
//根據(jù)索引數(shù)拼接最新的標(biāo)題,并綁定到button上
timer.map{"計(jì)數(shù)\($0)"}
.bind(to: button.rx.title(for: .normal))
.disposed(by: disposeBag)
按鈕富文本標(biāo)題(attributedTitle)的綁定
//創(chuàng)建一個(gè)計(jì)時(shí)器(每1秒發(fā)送一個(gè)索引數(shù))
let timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
//將已過(guò)去的時(shí)間格式化成想要的字符串疤剑,并綁定到button上
timer.map(formatTimeInterval)
.bind(to: button.rx.attributedTitle())
.disposed(by: disposeBag)
按鈕圖標(biāo)(image)的綁定
//創(chuàng)建一個(gè)計(jì)時(shí)器(每1秒發(fā)送一個(gè)索引數(shù))
let timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
//根據(jù)索引數(shù)選擇對(duì)應(yīng)的按鈕圖標(biāo)滑绒,并綁定到button上
timer.map({
let name = $0%2 == 0 ? "back" : "forward"
return UIImage(named: name)!
})
.bind(to: button.rx.image())
.disposed(by: disposeBag)
按鈕背景圖片(backgroundImage)的綁定
//創(chuàng)建一個(gè)計(jì)時(shí)器(每1秒發(fā)送一個(gè)索引數(shù))
let timer = Observable<Int>.interval(1, scheduler: MainScheduler.instance)
//根據(jù)索引數(shù)選擇對(duì)應(yīng)的按鈕背景圖闷堡,并綁定到button上
timer.map{ UIImage(named: "\($0%2)")! }
.bind(to: button.rx.backgroundImage())
.disposed(by: disposeBag)
按鈕是否可用(isEnabled)的綁定
switch1.rx.isOn
.bind(to: button1.rx.isEnabled)
.disposed(by: disposeBag)
按鈕是否選中(isSelected)的綁定
//默認(rèn)選中第一個(gè)按鈕
button1.isSelected = true
//強(qiáng)制解包,避免后面還需要處理可選類型
let buttons = [button1, button2, button3].map { $0! }
//創(chuàng)建一個(gè)可觀察序列疑故,它可以發(fā)送最后一次點(diǎn)擊的按鈕(也就是我們需要選中的按鈕)
let selectedButton = Observable.from(
buttons.map { button in button.rx.tap.map { button } }
).merge()
// Observable.from(buttons.map({ (btn) -> Observable<UIButton> in
// return btn.rx.tap.map({ return btn })
// }))
//對(duì)于每一個(gè)按鈕都對(duì)selectedButton進(jìn)行訂閱杠览,根據(jù)它是否是當(dāng)前選中的按鈕綁定isSelected屬性
for button in buttons {
selectedButton.map { $0 == button }
.bind(to: button.rx.isSelected)
.disposed(by: disposeBag)
}
-
UISwitch
switch1.rx.isOn.asObservable()
.subscribe(onNext: {
print("當(dāng)前開關(guān)狀態(tài):\($0)")
})
.disposed(by: disposeBag)
-
UISegmentedControl
segmented.rx.selectedSegmentIndex.asObservable()
.subscribe(onNext: {
print("當(dāng)前項(xiàng):\($0)")
})
.disposed(by: disposeBag)
-
UIActivityIndicatorView(活動(dòng)指示器)
mySwitch.rx.value
.bind(to: activityIndicator.rx.isAnimating)
.disposed(by: disposeBag)
-
UIApplication中的isNetworkActivityIndicatorVisible屬性
isNetworkActivityIndicatorVisible屬性是用于設(shè)置狀態(tài)欄中是否顯示活動(dòng)指示器
mySwitch.rx.value
.bind(to: UIApplication.shared.rx.isNetworkActivityIndicatorVisible)
.disposed(by: disposeBag)
-
UISlider(滑塊)
slider.rx.value.asObservable()
.subscribe(onNext: {
print("當(dāng)前值為:\($0)")
})
.disposed(by: disposeBag)
-
UIStepper(步進(jìn)器)
stepper.rx.value.asObservable()
.subscribe(onNext: {
print("當(dāng)前值為:\($0)")
})
.disposed(by: disposeBag)
// 使用滑塊(slider)來(lái)控制 stepper 的步長(zhǎng)
slider.rx.value
.map{ Double($0) } //由于slider值為Float類型,而stepper的stepValue為Double類型纵势,因此需要轉(zhuǎn)換
.bind(to: stepper.rx.stepValue)
.disposed(by: disposeBag)
-
UIGestureRecognizer
//添加一個(gè)上滑手勢(shì)
let swipe = UISwipeGestureRecognizer()
swipe.direction = .up
self.view.addGestureRecognizer(swipe)
//手勢(shì)響應(yīng)
swipe.rx.event
.subscribe(onNext: { [weak self] recognizer in
//這個(gè)點(diǎn)是滑動(dòng)的起點(diǎn)
let point = recognizer.location(in: recognizer.view)
self?.showAlert(title: "向上劃動(dòng)", message: "\(point.x) \(point.y)")
})
.disposed(by: disposeBag)
// 第二種綁定方法
swipe.rx.event
.bind { [weak self] recognizer in
//這個(gè)點(diǎn)是滑動(dòng)的起點(diǎn)
let point = recognizer.location(in: recognizer.view)
self?.showAlert(title: "向上劃動(dòng)", message: "\(point.x) \(point.y)")
}
.disposed(by: disposeBag)
-
UIDatePicker
日期選擇響應(yīng)
datePicker.rx.date .map { [weak self] in "當(dāng)前選擇時(shí)間: " + self!.dateFormatter.string(from: $0) } .bind(to: label.rx.text) .disposed(by: disposeBag)
倒計(jì)時(shí)
加 DispatchQueue.main.async 是為了解決第一次撥動(dòng)表盤不觸發(fā)值改變事件的問(wèn)題(這個(gè)是 iOS 的 bug)
//剩余時(shí)間與datepicker做雙向綁定
DispatchQueue.main.async{
_ = self.ctimer.rx.countDownDuration <-> self.leftTime
}
//綁定button標(biāo)題
Observable.combineLatest(leftTime.asObservable(), countDownStopped.asObservable()) {
leftTimeValue, countDownStoppedValue in
//根據(jù)當(dāng)前的狀態(tài)設(shè)置按鈕的標(biāo)題
if countDownStoppedValue {
return "開始"
}else{
return "倒計(jì)時(shí)開始踱阿,還有 \(Int(leftTimeValue)) 秒..."
}
}.bind(to: btnstart.rx.title())
.disposed(by: disposeBag)
//綁定button和datepicker狀態(tài)(在倒計(jì)過(guò)程中,按鈕和時(shí)間選擇組件不可用)
countDownStopped.asDriver().drive(ctimer.rx.isEnabled).disposed(by: disposeBag)
countDownStopped.asDriver().drive(btnstart.rx.isEnabled).disposed(by: disposeBag)
參考文章:Swift - RxSwift的使用詳解21(UI控件擴(kuò)展1:UILabel)
Swift - RxSwift的使用詳解22(UI控件擴(kuò)展2:UITextField钦铁、UITextView)
Swift - RxSwift的使用詳解23(UI控件擴(kuò)展3:UIButton软舌、UIBarButtonItem)
Swift - RxSwift的使用詳解24(UI控件擴(kuò)展4:UISwitch、UISegmentedControl)
Swift - RxSwift的使用詳解25(UI控件擴(kuò)展5:UIActivityIndicatorView育瓜、UIApplication)
Swift - RxSwift的使用詳解26(UI控件擴(kuò)展6:UISlider葫隙、UIStepper)
Swift - RxSwift的使用詳解28(UI控件擴(kuò)展7:UIGestureRecognizer)
Swift - RxSwift的使用詳解29(UI控件擴(kuò)展8:UIDatePicker)