使用 RxSwift,如何根据有效文本启用 UIButton?
Using RxSwift, How To Enable UIButton Based on Valid Text?
在 RxSwift/RxCocoa 2.0.0- beta 3 中,我有一个 ViewModel:
let someString = Variable("")
func isValidSomeString() -> Observable<Bool> {
if someString.value.characters.count == 0 {
return just(false)
}
return just(true)
}
我已经将 someString 绑定到 ViewController 中的文本字段。
每当 someString(或者可能是文本字段,如果这是更好的方式)发生变化时,我希望根据 someString 是否有效启用一个按钮。
我尝试使用 "Observable< Bool >",但开始走另一条路。我可以在 ViewController:
someViewModel.someString.subscribeNext { text -> Void in
// could just someUIButton.enabled = someViewModel.isValidSomeString(text)
}.addDisposableTo(disposeBag)
有没有比 isValidSomeString(text) 方法更简洁的方法?我们已经通过使用 combineLatest 的 returns Observable< Bool > 的 isValidLogin 取得了不错的成功。
听起来 Action
是在这种情况下使用的完美工具。您需要在 ViewModel 中创建一个 Action
,让它的 enabledIf
observable 成为字符串更改的结果,并将此操作连接到您的 UIButton
。这样按钮将自动启用。
在您的 ViewModel 中,您需要添加以下内容:
var buttonAction: CocoaAction {
let hasString = self.someString.map { ![=10=].isEmpty }
return CocoaAction(enabledIf: hasString) {
// do something when button tapped
return empty()
}
}
在将 ViewController 绑定到 ViewModel 时,您需要:
myButton.rx_action = viewModel.buttonAction
看起来你只需要 map
你的 someString
到 Obserable<Bool>
然后绑定到 rx_enabled
of UIButton
像这样:
someViewModel.someString
.asObservable()
.map { (str) -> Bool in
return someViewModel.isValidSomeString(text)
}
.bindTo(someUIButton.rx_enabled)
.addDisposableTo(disposeBag)
但我认为如果你的视图模型中有 Variable<Bool>
那种
会更简单
struct ViewModel {
....
canLogIn = Variable(false)
}
在这种情况下,您可以像这样将它绑定到 rx_enabled
:
let userNameValidation = loginTextField
.rx_text
.map({![=12=].isEmpty})
.shareReplay(1)
let passwordValidation = passwordTextField
.rx_text
.map({![=12=].isEmpty})
.shareReplay(1)
let loginEnabled = combineLatest(userNameValidation, passWordValidation) { (username, password) in
return username && password
}
loginEnabled
.bindTo(loginViewModel.canlogIn)
.addDisposableTo(disposeBag)
loginViewModel.canlogIn
.bindTo(loginButton.rx_enabled)
.addDisposableTo(disposeBag)
在 RxSwift/RxCocoa 2.0.0- beta 3 中,我有一个 ViewModel:
let someString = Variable("")
func isValidSomeString() -> Observable<Bool> {
if someString.value.characters.count == 0 {
return just(false)
}
return just(true)
}
我已经将 someString 绑定到 ViewController 中的文本字段。
每当 someString(或者可能是文本字段,如果这是更好的方式)发生变化时,我希望根据 someString 是否有效启用一个按钮。
我尝试使用 "Observable< Bool >",但开始走另一条路。我可以在 ViewController:
someViewModel.someString.subscribeNext { text -> Void in
// could just someUIButton.enabled = someViewModel.isValidSomeString(text)
}.addDisposableTo(disposeBag)
有没有比 isValidSomeString(text) 方法更简洁的方法?我们已经通过使用 combineLatest 的 returns Observable< Bool > 的 isValidLogin 取得了不错的成功。
听起来 Action
是在这种情况下使用的完美工具。您需要在 ViewModel 中创建一个 Action
,让它的 enabledIf
observable 成为字符串更改的结果,并将此操作连接到您的 UIButton
。这样按钮将自动启用。
在您的 ViewModel 中,您需要添加以下内容:
var buttonAction: CocoaAction {
let hasString = self.someString.map { ![=10=].isEmpty }
return CocoaAction(enabledIf: hasString) {
// do something when button tapped
return empty()
}
}
在将 ViewController 绑定到 ViewModel 时,您需要:
myButton.rx_action = viewModel.buttonAction
看起来你只需要 map
你的 someString
到 Obserable<Bool>
然后绑定到 rx_enabled
of UIButton
像这样:
someViewModel.someString
.asObservable()
.map { (str) -> Bool in
return someViewModel.isValidSomeString(text)
}
.bindTo(someUIButton.rx_enabled)
.addDisposableTo(disposeBag)
但我认为如果你的视图模型中有 Variable<Bool>
那种
struct ViewModel {
....
canLogIn = Variable(false)
}
在这种情况下,您可以像这样将它绑定到 rx_enabled
:
let userNameValidation = loginTextField
.rx_text
.map({![=12=].isEmpty})
.shareReplay(1)
let passwordValidation = passwordTextField
.rx_text
.map({![=12=].isEmpty})
.shareReplay(1)
let loginEnabled = combineLatest(userNameValidation, passWordValidation) { (username, password) in
return username && password
}
loginEnabled
.bindTo(loginViewModel.canlogIn)
.addDisposableTo(disposeBag)
loginViewModel.canlogIn
.bindTo(loginButton.rx_enabled)
.addDisposableTo(disposeBag)