4 votes

RxSwift et la propriété isSelected sur UIButton

J'ai trois boutons et je veux qu'ils ne puissent être sélectionnés qu'un seul à la fois :

enter image description here

et :

enter image description here

etc...

Mon approche est la suivante :

class MyController: UIViewController {

    @IBOutlet var buttonOne: UIButton!
    @IBOutlet var buttonTwo: UIButton!
    @IBOutlet var buttonThree: UIButton!

    var buttonOneIsSelected = Variable(true)
    var buttonTwoIsSelected = Variable(false)
    var buttonThreeIsSelected = Variable(false)

    override func viewDidLoad() {
        super.viewDidLoad()

        buttonOne.isSelected = true

        buttonOneIsSelected.asDriver()
            .drive(buttonOne.rx.isSelected)
            .disposed(by: disposeBag)
        buttonTwoIsSelected.asDriver()
            .drive(buttonTwo.rx.isSelected)
            .disposed(by: disposeBag)
        buttonThreeIsSelected.asDriver()
            .drive(buttonThree.rx.isSelected)
            .disposed(by: disposeBag)

        buttonOne.rx.tap.asObservable().map { (_) -> Bool in
            return !self.buttonOne.isSelected
        }
        .do(onNext: { (isSelected) in
            self.buttonTwoIsSelected.value = !isSelected
            self.buttonThreeIsSelected.value = !isSelected
        })
        .bindTo(buttonOne.rx.isSelected)
        .disposed(by: disposeBag)

        buttonTwo.rx.tap.asObservable().map { (_) -> Bool in
            return !self.buttonTwo.isSelected
            }
            .do(onNext: { (isSelected) in
                self.buttonOneIsSelected.value = !isSelected
                self.buttonThreeIsSelected.value = !isSelected
            })
            .bindTo(buttonTwo.rx.isSelected)
            .disposed(by: disposeBag)

        buttonThree.rx.tap.asObservable().map { (_) -> Bool in
            return !self.buttonThree.isSelected
            }
            .do(onNext: { (isSelected) in
                self.buttonOneIsSelected.value = !isSelected
                self.buttonTwoIsSelected.value = !isSelected
            })
            .bindTo(buttonThree.rx.isSelected)
            .disposed(by: disposeBag)
}

Existe-t-il une meilleure approche ? Cela fonctionne, mais existe-t-il un meilleur moyen "réactif" de le faire en utilisant RxSwift ?

12voto

tomahh Points 4141

Subject et par extension Variable ne sont la plupart du temps utiles que pour faire le pont entre le monde impératif et le monde réactif. Ici, vous pouvez vous en passer.

.do(onNext:) est également un moyen d'effectuer des effets secondaires, ce que vous ne voulez généralement pas dans votre code réactif.

// force unwrap to avoid having to deal with optionals later on
let buttons = [button1, button2, button3].map { $0! }

// create an observable that will emit the last tapped button (which is
// the one we want selected)
let selectedButton = Observable.from(
  buttons.map { button in button.rx.tap.map { button } }
).merge()

// for each button, create a subscription that will set its `isSelected`
// state on or off if it is the one emmited by selectedButton
buttons.reduce(Disposables.create()) { disposable, button in
    let subscription = selectedButton.map { $0 == button }
      .bindTo(button.rx.isSelected)

    // combine two disposable together so that we can simply call
    // .dispose() and the result of reduce if we want to stop all
    // subscriptions
    return Disposables.create(disposable, subscription)
}
.addDisposableTo(disposeBag)

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X