RxSwift - Show/hide 按下按钮时的警告标签

RxSwift - Show/hide warning label when button was pressed

我正在使用 MVVM 模式并尝试仅在用户按下登录按钮时显示警告标签。现在它们没有出现,因为我不知道如何仅在用户操作时显示它们。然后当用户开始编辑时,相应标签的警告应该隐藏。 这是我的 ViewController 处理对 viewModel 的引用:

import UIKit
import RxSwift
import RxCocoa
class RxLoginViewController: UIViewController {

    @IBOutlet weak var signInButton: UIButton!
    @IBOutlet weak var phoneNumberTextField: UITextField!
    @IBOutlet weak var passwordTextField: UITextField!
    @IBOutlet weak var phoneWarningLabel: UILabel!
    @IBOutlet weak var passwordWarningLabel: UILabel!

    fileprivate var viewModel: RxLoginViewModel?
    private let disposeBag = DisposeBag()

    override func viewDidLoad() {
        super.viewDidLoad()

        viewModel = RxLoginViewModel(phoneNumber: phoneNumberTextField.rx.text.orEmpty.asDriver(), passwordText: passwordTextField.rx.text.orEmpty.asDriver())
        addBindsToViewModel(viewModel: viewModel!)
        setupButtons()
    }

    fileprivate func addBindsToViewModel(viewModel: RxLoginViewModel) {
        phoneNumberTextField.rx.text
            .orEmpty
            .asObservable()
            .debug("phoneNumberTextField")
            .bindTo(viewModel.phoneNumberText)
            .addDisposableTo(disposeBag)

        passwordTextField.rx.text
            .orEmpty
            .asObservable()
            .debug("passwordTextField")
            .bindTo(viewModel.passwordText)
            .addDisposableTo(disposeBag)

        viewModel.showPhoneWarning
            .asDriver()
            .debug("showPhoneWarning")
            .drive(onNext: { [weak self] showWarning in
                UIView.animate(withDuration: 0.2) {
                    self?.phoneWarningLabel.isHidden = !showWarning
                }}
            )
            .addDisposableTo(disposeBag)

        viewModel.showPasswordWarning
            .asDriver()
            .debug("showPasswordWarning")
            .drive(onNext: { [weak self] showWarning in
                UIView.animate(withDuration: 0.2) {
                    self?.passwordWarningLabel.isHidden = !showWarning
                }
            })
            .addDisposableTo(disposeBag)

        viewModel.credentialsValid
            .debug("credentialsValid")
            .drive(onNext: { [weak self] valid in
                self?.signInButton.isEnabled = valid
                self?.signInButton.alpha = valid ? 1 : 0.5
            })
            .addDisposableTo(disposeBag)
    }

    private func setupButtons() {

        signInButton.rx.tap
            .bindTo(viewModel!.signInAction)
            .addDisposableTo(disposeBag)
    }
}

和视图模型:

class RxLoginViewModel {
    let dataManager = DataManager.sharedInstance()

    private let disposeBag = DisposeBag()

    //MARK: - Model proprties
    var phoneNumberText = Variable<String>("")
    var passwordText = Variable<String>("")
    var signInAction: Variable<Void> = Variable<Void>()

    var showPhoneWarning = Variable(false)
    var showPasswordWarning = Variable(false)
    var credentialsValid: Driver<Bool>
    var canLogIn = Variable(false)

    init(phoneNumber: Driver<String>, passwordText: Driver<String>) {

        let phoneValid = phoneNumber
            .distinctUntilChanged()
            .throttle(0.3)
            .map { ([=12=] =~ RegEx.phone) }

        let passwordValid = passwordText
            .distinctUntilChanged()
            .throttle(0.3)
            .map { ([=12=].utf8.count > 5) }

        credentialsValid = Driver.combineLatest(phoneValid, passwordValid) { [=12=] &&  }
        phoneNumber.debug("phone number driver")
            .drive(onNext: {_ in self.showPhoneWarning.value = false })
            .addDisposableTo(disposeBag)
        phoneNumber.debug("password driver")
            .drive(onNext: {_ in self.showPasswordWarning.value = false })
            .addDisposableTo(disposeBag)

        credentialsValid.asObservable()
            .bindTo(canLogIn)
            .addDisposableTo(disposeBag)

        // actions handler
        signInAction
            .asObservable()
            .debug("signInAction")
            .do(onNext: { _ in
                 // show warning for any invalid textfield
                 // filter both valid fields
            } )
            // sent url request
            .subscribe(onNext: { status in

                    self.dataManager.login(withPhone: self.phoneNumberText.value, email: "", password: self.passwordText.value, success: { ( result ) in
                    if let response = result as? [String : Any], response["aboutMe"] == nil {
                        self.dataManager.currentUser().userId = response["id"] as? NSNumber
//                        self.dataManager.update(.fillProfile)
                    }
                }, failure: { (error) in
//                    print(error.localizedDescription)

                })
            })
            .addDisposableTo(disposeBag)
}

我应该如何显示任何无效文本字段的警告以及如何过滤我的 ViewModel 中的两个有效字段?

我做视图模型的方式与您不同,但希望这对您有所帮助...

此处的关键是列出所有可能影响 showPhoneWarning 可观察对象的内容。

例如,如果 signInAction 进入而 phoneNumberText 无效,您希望 observable 发出 true。

让我们将其表示为一个变量:

let invalidPhoneNumberOnTap = source.phoneNumberText
    .map { [=10=].isValidPhoneNumber == false }
    .sample(source.signInAction)

如果 phoneNumberText 触发新元素,您还希望 observable 发出 false。

let hideWarning = source.phoneNumberText.map { _ in false }

现在您所要做的就是将这两个合并在一起。您还想确保它以 false 开头,这样警告就不会过早显示。

showPhoneWarning = Observable.of(invalidPhoneNumberOnTap, hideWarning)
    .merge()
    .startWith(false)

以大致相同的方式处理 showEmailWarning。