LoginSignup
3
2

More than 3 years have passed since last update.

[RxSwift]ユーザー登録フォーム制御実装

Last updated at Posted at 2019-08-14

はじめに

https://qiita.com/doi_daihei/items/6e0330debab12bcde155
こちらの第二弾ですね。
今回もアプリ開発においてよくあるユーザー登録画面をRxで書いてみました。
ユーザー登録画面のフォーム制御ってUITextFieldのdelegateで書くと、むずかしいというより、面倒くさいですよね。
しかも、コンポーネント化しているとどこでどの制御しているか複雑になっちゃいますよね。
でもRxを用いれば、簡単かつ明瞭にかけますのでそちらをご紹介致します!

成果物

デザインはクソですが、
エラーメッセージの見せ方やsubmitボタンの活性/非活性の制御に関してはwebとかでもよく見受ける挙動ですね。

user_register.gif

ソースコード

本来であれば、MVVMだとViewModelのinputに伝搬して...とかしないといけなかったり、通信したりなど色々抜けてはいますが
今回はあくまでフォームの制御ですので、そこに着目して書いていきます。

setup

setupに関しては、enumを用意し、
コンポーネント側に用意しておいた type にbindしているだけです。

    private func setup() {
        Observable.just(.username).bind(to: usernameFormView.rx.type).disposed(by: disposeBag)
        Observable.just(.email).bind(to: emailFormView.rx.type).disposed(by: disposeBag)
        Observable.just(.password).bind(to: passwordFormView.rx.type).disposed(by: disposeBag)
        Observable.just(.confirmPassword).bind(to: confirmPasswordFormView.rx.type).disposed(by: disposeBag)
    }

制御

Rxで制御しているのは主に以下です。

  • 個々のバリデーション結果をエラーメッセージのhiddenにbind
  • 全てのバリデーション結果をsubmitボタンのenableにbind

ソースで書くと以下のような感じですね。

    private func bind() {

        let username = usernameFormView.rx.textFieldText.orEmpty.share(replay: 1)                   // share reply
        let email = emailFormView.rx.textFieldText.orEmpty.share(replay: 1)                         // share reply
        let password = passwordFormView.rx.textFieldText.orEmpty.share(replay: 1)                   // share reply
        let confirmPassword = confirmPasswordFormView.rx.textFieldText.orEmpty.share(replay: 1)     // share reply

        // ユーザー名のエラーメッセージ
        username
            .filter { !$0.isEmpty }
            .map { $0.isValidUsername() }
            .bind(to: usernameFormView.rx.isCautionLabelHidden)
            .disposed(by: disposeBag)

        // メールアドレスのエラーメッセージ
        email
            .filter { !$0.isEmpty }
            .map { $0.isValidEmail() }
            .bind(to: emailFormView.rx.isCautionLabelHidden)
            .disposed(by: disposeBag)

        // パスワードのエラーメッセージ
        password
            .filter { !$0.isEmpty }
            .map { $0.isValidPassword() }
            .bind(to: passwordFormView.rx.isCautionLabelHidden)
            .disposed(by: disposeBag)

        // 確認パスワードのエラーメッセージ
        Observable
            .combineLatest(password, confirmPassword) { password, confirmPassword in
                password == confirmPassword
            }
            .bind(to: confirmPasswordFormView.rx.isCautionLabelHidden)
            .disposed(by: disposeBag)

        // 全てのバリデーション判定をcombineLatestで最新精査
        Observable
            .combineLatest(username, email, password, confirmPassword) { username, email, password, confirmPassword in
                 username.isValidUsername() && email.isValidEmail() && password.isValidPassword() && (password == confirmPassword)
            }
            .bind(to: submitButton.rx.isEnabled)
            .disposed(by: disposeBag)
    }

コンポーネント->VCで制御するプロパティ

余談ではありますが、usernameFormView.rx.textFieldTextemailFormView.rx.textFieldText のようなコンポーネント側のRx系変数をVC側で用いたい場合が多々発生します。
その場合は以下のように書いておけば、内部で書いてあるRxの変数のように扱えます。
元々あるRxの変数のように扱えますので、パッと見でわかりますよね。


// MARK: - Reactive Extension
extension Reactive where Base: FormView {

    var type: Binder<FormType> {
        return Binder(base) { view, type in
            view.titleLabel.text = type.title
            view.cautionLabel.text = type.caution
            view.textField.keyboardType = type.keyboardType
            view.textField.isSecureTextEntry = type.isSecureTextEntry
            view.textField.textContentType = type.textContentType
        }
    }

    var textFieldText: ControlProperty<String?> {
        return base.textField.rx.text
    }

    var isCautionLabelHidden: Binder<Bool> {
        return base.cautionLabel.rx.isHidden
    }
}

まとめ

本業の方のプロジェクトがそろそろ終わりそう(絶賛炎上中ですがw)なので、
次のプロジェクトではRxを布教して行けたらなと思います。
以下、ソースコードです。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2