UI控件擴(kuò)展

// .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)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末栽烂,一起剝皮案震驚了整個(gè)濱河市躏仇,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌腺办,老刑警劉巖焰手,帶你破解...
    沈念sama閱讀 219,490評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異怀喉,居然都是意外死亡书妻,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門躬拢,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)躲履,“玉大人,你說(shuō)我怎么就攤上這事聊闯」げ拢” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵菱蔬,是天一觀的道長(zhǎng)篷帅。 經(jīng)常有香客問(wèn)我,道長(zhǎng)拴泌,這世上最難降的妖魔是什么魏身? 我笑而不...
    開封第一講書人閱讀 58,957評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮蚪腐,結(jié)果婚禮上箭昵,老公的妹妹穿的比我還像新娘。我一直安慰自己回季,他們只是感情好家制,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評(píng)論 6 393
  • 文/花漫 我一把揭開白布掉房。 她就那樣靜靜地躺著,像睡著了一般慰丛。 火紅的嫁衣襯著肌膚如雪卓囚。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,754評(píng)論 1 307
  • 那天诅病,我揣著相機(jī)與錄音哪亿,去河邊找鬼。 笑死贤笆,一個(gè)胖子當(dāng)著我的面吹牛蝇棉,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播芥永,決...
    沈念sama閱讀 40,464評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼篡殷,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了埋涧?” 一聲冷哼從身側(cè)響起板辽,我...
    開封第一講書人閱讀 39,357評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎棘催,沒想到半個(gè)月后劲弦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡醇坝,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評(píng)論 3 338
  • 正文 我和宋清朗相戀三年邑跪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片呼猪。...
    茶點(diǎn)故事閱讀 40,137評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡画畅,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出宋距,到底是詐尸還是另有隱情轴踱,我是刑警寧澤,帶...
    沈念sama閱讀 35,819評(píng)論 5 346
  • 正文 年R本政府宣布乡革,位于F島的核電站寇僧,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏沸版。R本人自食惡果不足惜嘁傀,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望视粮。 院中可真熱鬧细办,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至茴肥,卻和暖如春坚踩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瓤狐。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工瞬铸, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人础锐。 一個(gè)月前我還...
    沈念sama閱讀 48,409評(píng)論 3 373
  • 正文 我出身青樓嗓节,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親皆警。 傳聞我的和親對(duì)象是個(gè)殘疾皇子拦宣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容