-
Notifications
You must be signed in to change notification settings - Fork 4.2k
/
UIControl+Rx.swift
102 lines (84 loc) · 3.38 KB
/
UIControl+Rx.swift
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
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
//
// UIControl+Rx.swift
// RxCocoa
//
// Created by Daniel Tartaglia on 5/23/15.
// Copyright © 2015 Krunoslav Zaher. All rights reserved.
//
#if os(iOS) || os(tvOS)
import RxSwift
import UIKit
extension Reactive where Base: UIControl {
/// Bindable sink for `enabled` property.
public var isEnabled: Binder<Bool> {
return Binder(self.base) { control, value in
control.isEnabled = value
}
}
/// Bindable sink for `selected` property.
public var isSelected: Binder<Bool> {
return Binder(self.base) { control, selected in
control.isSelected = selected
}
}
/// Reactive wrapper for target action pattern.
///
/// - parameter controlEvents: Filter for observed event types.
public func controlEvent(_ controlEvents: UIControlEvents) -> ControlEvent<()> {
let source: Observable<Void> = Observable.create { [weak control = self.base] observer in
MainScheduler.ensureExecutingOnScheduler()
guard let control = control else {
observer.on(.completed)
return Disposables.create()
}
let controlTarget = ControlTarget(control: control, controlEvents: controlEvents) {
control in
observer.on(.next(()))
}
return Disposables.create(with: controlTarget.dispose)
}
.takeUntil(deallocated)
return ControlEvent(events: source)
}
/// Creates a `ControlProperty` that is triggered by target/action pattern value updates.
///
/// - parameter controlEvents: Events that trigger value update sequence elements.
/// - parameter getter: Property value getter.
/// - parameter setter: Property value setter.
public func controlProperty<T>(
editingEvents: UIControlEvents,
getter: @escaping (Base) -> T,
setter: @escaping (Base, T) -> ()
) -> ControlProperty<T> {
let source: Observable<T> = Observable.create { [weak weakControl = base] observer in
guard let control = weakControl else {
observer.on(.completed)
return Disposables.create()
}
observer.on(.next(getter(control)))
let controlTarget = ControlTarget(control: control, controlEvents: editingEvents) { _ in
if let control = weakControl {
observer.on(.next(getter(control)))
}
}
return Disposables.create(with: controlTarget.dispose)
}
.takeUntil(deallocated)
let bindingObserver = Binder(base, binding: setter)
return ControlProperty<T>(values: source, valueSink: bindingObserver)
}
/// This is a separate method is to better communicate to public consumers that
/// an `editingEvent` needs to fire for control property to be updated.
internal func controlPropertyWithDefaultEvents<T>(
editingEvents: UIControlEvents = [.allEditingEvents, .valueChanged],
getter: @escaping (Base) -> T,
setter: @escaping (Base, T) -> ()
) -> ControlProperty<T> {
return controlProperty(
editingEvents: [.allEditingEvents, .valueChanged],
getter: getter,
setter: setter
)
}
}
#endif