【问题标题】:RxSwift - Show/hide warning label when button was pressedRxSwift - 按下按钮时显示/隐藏警告标签
【发布时间】:2017-04-24 16:53:04
【问题描述】:

我正在使用 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)
    }
}

和 ViewModel:

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)
}

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

【问题讨论】:

    标签: ios swift mvvm reactive-cocoa rx-swift


    【解决方案1】:

    我的视图模型与您的做法不同,但希望这会帮助您...

    这里的关键是概述可能影响showPhoneWarning observable 的所有内容。

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

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

    let invalidPhoneNumberOnTap = source.phoneNumberText
        .map { $0.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。

    【讨论】:

      猜你喜欢
      • 2016-09-02
      • 1970-01-01
      • 1970-01-01
      • 2011-07-07
      • 2023-03-09
      • 2011-06-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多