为有牺牲多壮志,敢教日月换新天。

[RxSwift教程]19、特征序列3:ControlProperty、 ControlEvent

★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤微信公众号:山青咏芝(let_us_code)
➤博主域名:https://www.zengqiang.org
➤GitHub地址:https://github.com/strengthen/LeetCode
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

强烈推荐!!!试用博主个人App作品!提需求!提建议!
App Store搜索:【Mind Draft
中国区可直接点击跳转:【Mind Draft

五、ControlProperty

1,基本介绍

(1)ControlProperty 是专门用来描述 UI 控件属性,拥有该类型的属性都是被观察者(Observable)。
(2)ControlProperty 具有以下特征:
  • 不会产生 error 事件
  • 一定在 MainScheduler 订阅(主线程订阅)
  • 一定在 MainScheduler 监听(主线程监听)
  • 共享状态变化
 

2,使用样例

(1)其实在 RxCocoa 下许多 UI 控件属性都是被观察者(可观察序列)。比如我们查看源码(UITextField+Rx.swift),可以发现 UITextField 的 rx.text 属性类型便是 ControlProperty<String?>:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import RxSwift
import UIKit
 
extension Reactive where BaseUITextField {
 
    public var text: ControlProperty<String?> {
        return value
    }
 
    public var value: ControlProperty<String?> {
        return base.rx.controlPropertyWithDefaultEvents(
            getter: { textField in
                textField.text
        },
            setter: { textField, value in
                if textField.text != value {
                    textField.text = value
                }
        }
        )
    }
     
    //......
}


(2)那么我们如果想让一个 textField 里输入内容实时地显示在另一个 label 上,即前者作为被观察者,后者作为观察者。可以这么写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import UIKit
import RxSwift
import RxCocoa
 
class ViewControllerUIViewController {
     
    @IBOutlet weak var textField: UITextField!
     
    @IBOutlet weak var label: UILabel!
     
    let disposeBag = DisposeBag()
     
    override func viewDidLoad() {
         
        //将textField输入的文字绑定到label上
        textField.rx.text
            .bind(to: label.rx.text)
            .disposed(by: disposeBag)
    }
}
 
extension UILabel {
    public var fontSize: Binder<CGFloat> {
        return Binder(self) { label, fontSize in
            label.font = UIFont.systemFont(ofSize: fontSize)
        }
    }
}


(3)运行结果如下:

原文:Swift - RxSwift的使用详解19(特征序列3:ControlProperty、 ControlEvent)

六 、ControlEvent

1,基本介绍

(1)ControlEvent 是专门用于描述 UI 所产生的事件,拥有该类型的属性都是被观察者(Observable)。
(2)ControlEvent 和 ControlProperty 一样,都具有以下特征:
  • 不会产生 error 事件
  • 一定在 MainScheduler 订阅(主线程订阅)
  • 一定在 MainScheduler 监听(主线程监听)
  • 共享状态变化
 

2,使用样例

(1)同样地,在 RxCocoa 下许多 UI 控件的事件方法都是被观察者(可观察序列)。比如我们查看源码(UIButton+Rx.swift),可以发现 UIButton 的 rx.tap 方法类型便是 ControlEvent<Void>:
1
2
3
4
5
6
7
8
import RxSwift
import UIKit
 
extension Reactive where BaseUIButton {
    public var tap: ControlEvent<Void> {
        return controlEvent(.touchUpInside)
    }
}


(2)那么我们如果想实现当一个 button 被点击时,在控制台输出一段文字。即前者作为被观察者,后者作为观察者。可以这么写:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import UIKit
import RxSwift
import RxCocoa
 
class ViewControllerUIViewController {
     
    let disposeBag = DisposeBag()
     
    @IBOutlet weak var button: UIButton!
     
    override func viewDidLoad() {
         
        //订阅按钮点击事件
        button.rx.tap
            .subscribe(onNext: {
                print("欢迎访问hangge.com")
            }).disposed(by: disposeBag)
    }
}


(3)运行结果如下:

    原文:Swift - RxSwift的使用详解19(特征序列3:ControlProperty、 ControlEvent)      原文:Swift - RxSwift的使用详解19(特征序列3:ControlProperty、 ControlEvent)
 

附:给 UIViewController 添加 RxSwift 扩展

1,UIViewController+Rx.swift

这里我们对 UIViewController 进行扩展:

  • 将 viewDidLoad、viewDidAppear、viewDidLayoutSubviews 等各种 ViewController 生命周期的方法转成 ControlEvent 方便在 RxSwift 项目中使用。
  • 增加 isVisible 序列属性,方便对视图的显示状态进行订阅。
  • 增加 isDismissing 序列属性,方便对视图的释放进行订阅。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
import UIKit
import RxCocoa
import RxSwift
 
public extension Reactive where BaseUIViewController {
    public var viewDidLoad: ControlEvent<Void> {
        let source = self.methodInvoked(#selector(Base.viewDidLoad)).map { _ in }
        return ControlEvent(events: source)
    }
     
    public var viewWillAppear: ControlEvent<Bool> {
        let source = self.methodInvoked(#selector(Base.viewWillAppear))
            .map { $0.first asBool ?? false }
        return ControlEvent(events: source)
    }
    public var viewDidAppear: ControlEvent<Bool> {
        let source = self.methodInvoked(#selector(Base.viewDidAppear))
            .map { $0.first asBool ?? false }
        return ControlEvent(events: source)
    }
     
    public var viewWillDisappear: ControlEvent<Bool> {
        let source = self.methodInvoked(#selector(Base.viewWillDisappear))
            .map { $0.first asBool ?? false }
        return ControlEvent(events: source)
    }
    public var viewDidDisappear: ControlEvent<Bool> {
        let source = self.methodInvoked(#selector(Base.viewDidDisappear))
            .map { $0.first asBool ?? false }
        return ControlEvent(events: source)
    }
     
    public var viewWillLayoutSubviews: ControlEvent<Void> {
        let source = self.methodInvoked(#selector(Base.viewWillLayoutSubviews))
            .map { _ in }
        return ControlEvent(events: source)
    }
    public var viewDidLayoutSubviews: ControlEvent<Void> {
        let source = self.methodInvoked(#selector(Base.viewDidLayoutSubviews))
            .map { _ in }
        return ControlEvent(events: source)
    }
     
    public var willMoveToParentViewController: ControlEvent<UIViewController?> {
        let source = self.methodInvoked(#selector(Base.willMove))
            .map { $0.first asUIViewController }
        return ControlEvent(events: source)
    }
    public var didMoveToParentViewController: ControlEvent<UIViewController?> {
        let source = self.methodInvoked(#selector(Base.didMove))
            .map { $0.first asUIViewController }
        return ControlEvent(events: source)
    }
     
    public var didReceiveMemoryWarning: ControlEvent<Void> {
        let source = self.methodInvoked(#selector(Base.didReceiveMemoryWarning))
            .map { _ in }
        return ControlEvent(events: source)
    }
     
    //表示视图是否显示的可观察序列,当VC显示状态改变时会触发
    public var isVisible: Observable<Bool> {
        let viewDidAppearObservable = self.base.rx.viewDidAppear.map { _ in true }
        let viewWillDisappearObservable = self.base.rx.viewWillDisappear
            .map { _ in false }
        return Observable<Bool>.merge(viewDidAppearObservable,
                                      viewWillDisappearObservable)
    }
     
    //表示页面被释放的可观察序列,当VC被dismiss时会触发
    public var isDismissing: ControlEvent<Bool> {
        let source = self.sentMessage(#selector(Base.dismiss))
            .map { $0.first asBool ?? false }
        return ControlEvent(events: source)
    }
}

 

2,使用样例

(1)通过扩展,我们可以直接对 VC 的各种方法进行订阅。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import UIKit
import RxSwift
import RxCocoa
 
class ViewControllerUIViewController {
 
    let disposeBag = DisposeBag()
     
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
         
        //页面显示状态完毕
        self.rx.isVisible
            .subscribe(onNext: { visible in
                print("当前页面显示状态:\(visible)")
            }).disposed(by: disposeBag)
         
        //页面加载完毕
        self.rx.viewDidLoad
            .subscribe(onNext: {
                print("viewDidLoad")
            }).disposed(by: disposeBag)
         
        //页面将要显示
        self.rx.viewWillAppear
            .subscribe(onNext: { animated in
                print("viewWillAppear")
            }).disposed(by: disposeBag)
         
        //页面显示完毕
        self.rx.viewDidAppear
            .subscribe(onNext: { animated in
                print("viewDidAppear")
            }).disposed(by: disposeBag)
    }
     
    override func viewDidLoad() {
        super.viewDidLoad()
    }
}


(2)运行结果如下:

原文:Swift - RxSwift的使用详解19(特征序列3:ControlProperty、 ControlEvent)
posted @ 2020-09-15 20:01  为敢技术  阅读(762)  评论(0编辑  收藏  举报