RxSwift - 按下按钮时显示/隐藏警告标签

问题描述:

我正在使用MVVM模式,并尝试仅在用户按登录按钮时才显示警告标签。现在他们没有出现,因为我不知道如何仅以用户操作显示它们。然后在用户开始编辑时,应该隐藏相应标签的警告。 这里是我的ViewController该处理参考视图模型:RxSwift - 按下按钮时显示/隐藏警告标签

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 { ($0 =~ RegEx.phone) } 

     let passwordValid = passwordText 
      .distinctUntilChanged() 
      .throttle(0.3) 
      .map { ($0.utf8.count > 5) } 

     credentialsValid = Driver.combineLatest(phoneValid, passwordValid) { $0 && $1 } 
     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) 
} 

我应该怎么做,以示对任何无效的文本框警告以及如何过滤在我的视图模型都有效字段?

我没有做我的视图模型你做同样的方式,但希望这将帮助你......

这里的关键是要勾勒一切可以影响showPhoneWarning观察到。

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

让我们表达作为一个变量:

let invalidPhoneNumberOnTap = source.phoneNumberText 
    .map { $0.isValidPhoneNumber == false } 
    .sample(source.signInAction) 

你也想,如果phoneNumberText火灾的新元素可观察到发射假。

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

现在您只需将两者合并即可。您还想确保它以false开头,因此警告不会过早显示。

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

以几乎相同的方式处理showEmailWarning。