UIControl+Rx.swift 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. //
  2. // UIControl+Rx.swift
  3. // RxCocoa
  4. //
  5. // Created by Daniel Tartaglia on 5/23/15.
  6. // Copyright © 2015 Krunoslav Zaher. All rights reserved.
  7. //
  8. #if os(iOS) || os(tvOS)
  9. import RxSwift
  10. import UIKit
  11. extension Reactive where Base: UIControl {
  12. /// Bindable sink for `enabled` property.
  13. public var isEnabled: Binder<Bool> {
  14. return Binder(self.base) { control, value in
  15. control.isEnabled = value
  16. }
  17. }
  18. /// Bindable sink for `selected` property.
  19. public var isSelected: Binder<Bool> {
  20. return Binder(self.base) { control, selected in
  21. control.isSelected = selected
  22. }
  23. }
  24. /// Reactive wrapper for target action pattern.
  25. ///
  26. /// - parameter controlEvents: Filter for observed event types.
  27. public func controlEvent(_ controlEvents: UIControl.Event) -> ControlEvent<()> {
  28. let source: Observable<Void> = Observable.create { [weak control = self.base] observer in
  29. MainScheduler.ensureRunningOnMainThread()
  30. guard let control = control else {
  31. observer.on(.completed)
  32. return Disposables.create()
  33. }
  34. let controlTarget = ControlTarget(control: control, controlEvents: controlEvents) { _ in
  35. observer.on(.next(()))
  36. }
  37. return Disposables.create(with: controlTarget.dispose)
  38. }
  39. .takeUntil(deallocated)
  40. return ControlEvent(events: source)
  41. }
  42. /// Creates a `ControlProperty` that is triggered by target/action pattern value updates.
  43. ///
  44. /// - parameter controlEvents: Events that trigger value update sequence elements.
  45. /// - parameter getter: Property value getter.
  46. /// - parameter setter: Property value setter.
  47. public func controlProperty<T>(
  48. editingEvents: UIControl.Event,
  49. getter: @escaping (Base) -> T,
  50. setter: @escaping (Base, T) -> Void
  51. ) -> ControlProperty<T> {
  52. let source: Observable<T> = Observable.create { [weak weakControl = base] observer in
  53. guard let control = weakControl else {
  54. observer.on(.completed)
  55. return Disposables.create()
  56. }
  57. observer.on(.next(getter(control)))
  58. let controlTarget = ControlTarget(control: control, controlEvents: editingEvents) { _ in
  59. if let control = weakControl {
  60. observer.on(.next(getter(control)))
  61. }
  62. }
  63. return Disposables.create(with: controlTarget.dispose)
  64. }
  65. .takeUntil(deallocated)
  66. let bindingObserver = Binder(base, binding: setter)
  67. return ControlProperty<T>(values: source, valueSink: bindingObserver)
  68. }
  69. /// This is a separate method to better communicate to public consumers that
  70. /// an `editingEvent` needs to fire for control property to be updated.
  71. internal func controlPropertyWithDefaultEvents<T>(
  72. editingEvents: UIControl.Event = [.allEditingEvents, .valueChanged],
  73. getter: @escaping (Base) -> T,
  74. setter: @escaping (Base, T) -> Void
  75. ) -> ControlProperty<T> {
  76. return controlProperty(
  77. editingEvents: editingEvents,
  78. getter: getter,
  79. setter: setter
  80. )
  81. }
  82. }
  83. #endif