【问题标题】:RxSwift enable/disable button based on textfield input基于文本字段输入的 RxSwift 启用/禁用按钮
【发布时间】:2021-04-24 21:02:37
【问题描述】:

我必须使用 RxSwift MVVM 实现以下场景

我有两个文本字段(OTP 和确认 OTP)和一个提交按钮,如果用户在 OTP 文本字段上没有值时单击 OTP 文本字段,那么提交按钮应该被禁用,现在如果用户在 otp 文本字段按钮中键入内容应该启用。现在,如果用户点击第二个文本字段,因为它现在是空白的,那么按钮应该再次被禁用,并且只有在有值时才会启用。

所以基本上我想通过检查来启用/禁用按钮:

  1. 如果 OTP 字段有值,则启用按钮,如果没有值则禁用它
  2. 用户点击确认 OTP 字段,现在它是空的,所以再次禁用该按钮
  3. 如果用户从 OTP 字段中删除值,请再次禁用按钮(因为它是空的,与 Confirm OTP 字段相同)

谢谢

【问题讨论】:

  • 如果两个字段都不是第一响应者怎么办?
  • @Daniel T. 按钮将被禁用,但在我的情况下,OTP 字段始终是视图加载时的第一响应者,此时需要禁用按钮

标签: ios swift xcode mvvm rx-swift


【解决方案1】:

更新答案:

正如@Daniel T. 所说,这可以在不使用主题的情况下解决:

let disposeBag = DisposeBag()

let otpFieldIsFocused = Observable.merge(
    otpField.rx.controlEvent(.editingDidBegin).map { true },
    otpField.rx.controlEvent(.editingDidEnd).map { false }
)

// Sends only when the field is first responder
let otpFieldIsNotEmpty = otpField.rx.text.orEmpty
    .map { $0.isEmpty }
    .withLatestFrom(otpFieldIsFocused) {
        (isEmpty: $0, isFocused: $1)
    }
    .filter { $0.isFocused }
    .map { !$0.isEmpty }

let otpConfirmFieldIsFocused = Observable<Bool>.merge(
    otpConfirmField.rx.controlEvent(.editingDidBegin).map { true },
    otpConfirmField.rx.controlEvent(.editingDidEnd).map { false }
)

let otpConfirmFieldIsNotEmpty = otpConfirmField.rx.text.orEmpty
    .map { $0.isEmpty }
    .withLatestFrom(otpConfirmFieldIsFocused) {
        (isEmpty: $0, isFocused: $1)
    }
    .filter { $0.isFocused }
    .map { !$0.isEmpty }

Observable.merge(otpFieldIsNotEmpty, otpConfirmFieldIsNotEmpty)
    .startWith(false)
    .bind(to: button.rx.isEnabled)
    .disposed(by: disposeBag)

旧答案:

这可以使用switchLatest 语句来完成:

import RxSwift
import RxCocoa

...

let disposeBag = DisposeBag()
let subject = PublishSubject<Observable<String>>()

otpField.rx
    .controlEvent(.editingDidBegin)
    .subscribe(onNext: {
        subject.onNext(otpField.rx.text.orEmpty.asObservable())
    })
    .disposed(by: disposeBag)

otpConfirmField.rx
    .controlEvent(.editingDidBegin)
    .subscribe(onNext: {
        subject.onNext(otpConfirmField.rx.text.orEmpty.asObservable())
    })
    .disposed(by: disposeBag)

subject
    .switchLatest()
    .map { !$0.isEmpty }
    .startWith(false)
    .distinctUntilChanged()
    .bind(to: button.rx.isEnabled)
    .disposed(by: disposeBag)

otpField.becomeFirstResponder()

如果您需要禁用按钮,例如,当两个字段都失去焦点时,您可以这样做:

subject.onNext(.just(""))

【讨论】:

  • 不需要主题。我建议您更好地考虑不变量并将其删除。否则,这是一个有趣的答案!
  • @andruvs 按钮未启用,即使我在文本字段中输入了某些内容。
  • @Daniel T. 感谢您的评论,我更新了答案。
猜你喜欢
  • 1970-01-01
  • 2021-07-15
  • 2012-01-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-08
  • 1970-01-01
  • 2010-12-04
相关资源
最近更新 更多