jonaszmclaren
jonaszmclaren

Reputation: 2489

RxSwift validation button color is not set properly

I'm using RxSwift to validate input from user, if everything is valid I want to enable a button and change its color. In my button class I have created Variable<Bool>:

var valid = Variable(false)

In initWithCoder I'm doing such thing:

valid.asObservable()
    .subscribe(onNext:  { [weak self] valid in
        self?.isEnabled = valid
        self?.titleLabel?.textColor = valid ? .white : .black
    })
    .addDisposableTo(disposeBag)

I have a method that validates input and returns an Observable<Bool> called validateDate() (I won't post it here for brevity):

let dataValid = viewModel.validateData()

dataValid
    .bind(to: submitButton.valid)
    .addDisposableTo(disposeBag)

The problem is, that although the valid value in subscription is correct and enabling button works perfectly, setting button's color does not work properly, because it seems like it changes color on next emission, not when valid became true.

Am I doing something wrong here? I would be thankful for any help.

Upvotes: 1

Views: 2584

Answers (2)

Mark Gilchrist
Mark Gilchrist

Reputation: 2032

Swift 4, RxCocoa 4 has now dropped UIBindingObserver in favour of Binder

extension Reactive where Base : UIButton {
   public var valid : Binder<Bool> {
        return Binder(self.base) { button, valid in
            button.isEnabled = valid
            button.setTitleColor(valid ? .white : .black, for: .normal)
        }
    }
}

Upvotes: 4

iWheelBuy
iWheelBuy

Reputation: 5679

Have you tried setTitleColor to change button's title color?

You might consider using UIBindingObserver for UI bindings:

import PlaygroundSupport
import UIKit
import RxSwift
import RxCocoa

extension Reactive where Base: UIButton {

    var valid: AnyObserver<Bool> {
        return UIBindingObserver(UIElement: base, binding: { (button: UIButton, valid: Bool) in
            button.isEnabled = valid
            button.setTitleColor(valid ? .white : .black, for: .normal)
        }).asObserver()
    }
}

let button = UIButton()
button.frame = CGRect(x: 0, y: 0, width: 100, height: 50)
button.backgroundColor = UIColor.orange
button.setTitle("Title", for: .normal)
Observable<Int>
    .timer(0, period: 1, scheduler: MainScheduler.instance)
    .map({ $0 % 2 == 0})
    .bind(to: button.rx.valid)

PlaygroundPage.current.liveView = button

Upvotes: 6

Related Questions