2017-05-04 3 views
1

UIControl의 사용자 정의 서브 클래스를 작성 중입니다. (그 draw 메소드를 재정의해야합니다.) isSelected 특성을 내 모델에 바인드하기 위해 RxSwift를 추가하고 싶습니다.RxSwift가있는 사용자 정의 UIControl 서브 클래스

지금까지 그렇게 좋았습니다. 이것은 잘 작동합니다.

내 문제는 사용자 touchUpInside 이벤트에 응답하여 isSelected 속성을 변경하는 방법입니다.

내 첫 번째 시도는 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) 
     }) 

    } 
} 

감사합니다. 당신이 UIControl로부터 서브 클래스 화하는 경우

+0

당신은 또한'RxCocoa'을 사용하고 있습니까? – ozgur

+0

RxCocoa도 사용합니다. – t4ncr3d3

답변

2

, 당신은 당신의 자신의 컨트롤 클래스를 만들고 당신은 제어 작업을 당신이 원하는 방법을 하나 이상 beginTracking(_:with:), continueTracking(_:with:), endTracking(_:with:), 또는 cancelTracking(with:)를 재정의해야합니다. 그런 다음 올바른 이벤트와 함께 sendActions(for:)으로 전화하십시오. UIControl의 용기에는 Rx가 없습니다. 그것을 강조하고 자체 unhighlight 수 있지만있는 UIButton에서 큐를 복용

, 컨트롤은 자신을 선택하지한다 (사용자의 손가락 예를 들어 그것에됩니다.)

당신이 제대로 UIControl, 코드를 작성하면 outside 컨트롤은 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 
     } 
    } 
} 
관련 문제