问题
I have three buttons and I want them to be selected only one at a time:
and:
etc...
My approach is this:
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)
}
Is there a better approach? It works, but is there a better 'reactive' way to do it by using RxSwift?
回答1:
Subject
and by extension Variable
are most of the time only useful when bridging from imperative to reactive world. Here, you could do without them.
.do(onNext:)
is also a way to perform side effect, something you usually don't want in your reactive code.
// 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)
来源:https://stackoverflow.com/questions/42318755/rxswift-and-isselected-property-on-uibutton