2017-05-04 135 views
1

我正在创建UIControl的自定义子类(我需要重写它的绘制方法),我想添加RxSwift以将其isSelected属性绑定到我的模型。RxSwift自定义UIControl子类

到目前为止这么好。这工作正常。

我的问题是我怎样才能改变值isSelected财产响应用户touchUpInside事件?

我的第一次尝试是使用UIControl的addTarget方法,但改变程序不被ControlProperty报道(如文档规定)的isSelected的价值。但我可以想出另一种解决方法。

任何帮助表示赞赏。子类的

的源代码:

class SYYesNoButton: UIControl { 

override init(frame: CGRect) { 
    super.init(frame: frame) 

    // subscribe to touchUpInside event 

    addTarget(
     self, 
     action: #selector(userDidTouchUpInside), 
     for: UIControlEvents.touchUpInside) 
} 



func userDidTouchUpInside() { 

    // change the value of the property 
    // this does not work, 
    // the change is not reported to the ControlProperty 
    // HOW CAN I CHANGE THIS ?? 

    self.isSelected = !isSelected 
} 

} 

扩展增加无功支持:

extension SYYesNoButton { 

    var rx_isSelected: ControlProperty<Bool> { 

    return UIControl.valuePublic(
     self, 
     getter: { (button) -> Bool in 
      return button.isSelected 
    }, 
     setter: { (button, value) in 
      button.isSelected = value 
    }) 


    } 
} 



extension UIControl { 

    static func valuePublic<T, ControlType: UIControl>(_ control: ControlType, getter: @escaping (ControlType) -> T, setter: @escaping (ControlType, T) ->()) -> ControlProperty<T> { 



     let values: Observable<T> = Observable.deferred { [weak control] in 
      guard let existingSelf = control else { 
       return Observable.empty() 
      } 

      return (existingSelf as UIControl).rx.controlEvent([.allEditingEvents, .valueChanged]) 
       .flatMap { _ in 
        return control.map { Observable.just(getter($0)) } ?? Observable.empty() 
       } 
       .startWith(getter(existingSelf)) 
     } 


     return ControlProperty(values: values, valueSink: UIBindingObserver(UIElement: control) { control, value in 
      setter(control, value) 
     }) 

    } 
} 

感谢所有。

+0

你是不是也使用'RxCocoa'? – ozgur

+0

我也使用RxCocoa – t4ncr3d3

回答

2

如果从UIControl继承,那么你在做自己的控件类,你必须覆盖一个或多个beginTracking(_:with:)continueTracking(_:with:)endTracking(_:with:),或cancelTracking(with:)使控制工作,你所希望的方式。然后用正确的事件呼叫sendActions(for:)。 UIControl的胆量不会有Rx。

以从UIButton的队列,你的控制不应选择本身,虽然它可以突出和unhighlight本身(当用户的手指在上面的例子)。

一旦你正确地创建了UIControl,代码外部控制器可以使用Rx观察它,而不需要额外的工作。

以下工作:

class ViewController: UIViewController { 

    @IBOutlet weak var yesNoButton: SYYesNoButton! 

    override func viewDidLoad() { 
     super.viewDidLoad() 

     yesNoButton.rx.controlEvent(.touchUpInside) 
      .scan(false, accumulator: { !$0.0 }) 
      .bind(to: yesNoButton.rx.isSelected) 
      .disposed(by: bag) 
    } 

    let bag = DisposeBag() 
} 

@IBDesignable 
class SYYesNoButton: UIControl { 

    override func layoutSubviews() { 
     super.layoutSubviews() 
     backgroundColor = isSelected ? .green : .red 
    } 

    override var isSelected: Bool { 
     didSet { 
      super.isSelected = isSelected 
      backgroundColor = isSelected ? .green : .red 
     } 
    } 
} 
相关问题