美文网首页swift
Swift - RxSwift的使用详解55(一个用户注册样例2

Swift - RxSwift的使用详解55(一个用户注册样例2

作者: 八级大狂风AM | 来源:发表于2018-05-07 16:12 被阅读649次

            当我们发起网络请求,或者进行其他一些比较耗时的操作时,最好给用户一个指示。比如上文的用户注册样例,当点击注册按钮后会等待 1.5 秒才返回结果,那么为了更好的用户体验这时就可以显示个活动指示器。

            下面我通过样例演示几种不同的活动指示器用法,以及他们如何根据请求操作自动进行隐藏和显示。

    一、准备工作

    1,引入 ActivityIndicator

    (1)ActivityIndicator 类可不是苹果自带的 UIActivityIndicator,它是一个用来监测是否有序列正在发送元素的类:

    • 如果至少还有一个序列正在工作,那么它会返回一个 true
    • 如果没有序列在工作了,那么它会返回一个 false 值。

    (2)默认情况下项目引入的 RxSwiftRxCocoa 库中是不会有个类的,我们需要手动将 RxSwift 源码包中的 RxExample/Services/ActivityIndicator.swift 这个文件添加到我们项目中来。

    2,修改 ViewModel

    (1)接着对前文的 GitHubSignupViewModel 做个修改,增加了个 signingIn 序列,用于表示当前是否正在“发请求注册中”。

    (2)我们在请求序列中使用 trackActivity 方法可以把这个请求序列放入制定的 activityIndicator 中进行监测,监测结果则做为 signingIn 序列。

    import RxSwift
    import RxCocoa
     
    class GitHubSignupViewModel {
         
        //用户名验证结果
        let validatedUsername: Driver<ValidationResult>
         
        //密码验证结果
        let validatedPassword: Driver<ValidationResult>
         
        //再次输入密码验证结果
        let validatedPasswordRepeated: Driver<ValidationResult>
         
        //注册按钮是否可用
        let signupEnabled: Driver<Bool>
         
        //正在注册中
        let signingIn: Driver<Bool>
         
        //注册结果
        let signupResult: Driver<Bool>
         
        //ViewModel初始化(根据输入实现对应的输出)
        init(
            input: (
            username: Driver<String>,
            password: Driver<String>,
            repeatedPassword: Driver<String>,
            loginTaps: Signal<Void>
            ),
            dependency: (
            networkService: GitHubNetworkService,
            signupService: GitHubSignupService
            )) {
             
            //用户名验证
            validatedUsername = input.username
                .flatMapLatest { username in
                    return dependency.signupService.validateUsername(username)
                        .asDriver(onErrorJustReturn: .failed(message: "服务器发生错误!"))
            }
             
            //用户名密码验证
            validatedPassword = input.password
                .map { password in
                    return dependency.signupService.validatePassword(password)
            }
             
            //重复输入密码验证
            validatedPasswordRepeated = Driver.combineLatest(
                input.password,
                input.repeatedPassword,
                resultSelector: dependency.signupService.validateRepeatedPassword)
             
            //注册按钮是否可用
            signupEnabled = Driver.combineLatest(
                validatedUsername,
                validatedPassword,
                validatedPasswordRepeated
            ) { username, password, repeatPassword in
                username.isValid && password.isValid && repeatPassword.isValid
                }
                .distinctUntilChanged()
             
            //获取最新的用户名和密码
            let usernameAndPassword = Driver.combineLatest(input.username, input.password) {
                (username: $0, password: $1) }
             
            //用于检测是否正在请求数据
            let activityIndicator = ActivityIndicator()
            self.signingIn = activityIndicator.asDriver()
             
            //注册按钮点击结果
            signupResult = input.loginTaps.withLatestFrom(usernameAndPassword)
                .flatMapLatest { pair in
                    return dependency.networkService.signup(pair.username,
                                                            password: pair.password)
                        .trackActivity(activityIndicator) //把当前序列放入signing序列中进行检测
                        .asDriver(onErrorJustReturn: false)
            }
        }
    }
    

    二、顶部状态栏联网指示器的绑定

    1,效果图

    (1)当我们点击注册按钮发起请求时,顶部状态栏会显示菊花状的网络请求指示器。

    (2)当注册结果返回时,顶部的网络请求指示器消失。

    2,样例代码

    这个只需要在主视图控制器中将 signingIn 绑定到 UIApplicationisNetworkActivityIndicatorVisible 属性上即可。

    import UIKit
    import RxSwift
    import RxCocoa
     
    class ViewController: UIViewController {
        //用户名输入框、以及验证结果显示标签
        @IBOutlet weak var usernameOutlet: UITextField!
        @IBOutlet weak var usernameValidationOutlet: UILabel!
         
        //密码输入框、以及验证结果显示标签
        @IBOutlet weak var passwordOutlet: UITextField!
        @IBOutlet weak var passwordValidationOutlet: UILabel!
         
        //重复密码输入框、以及验证结果显示标签
        @IBOutlet weak var repeatedPasswordOutlet: UITextField!
        @IBOutlet weak var repeatedPasswordValidationOutlet: UILabel!
         
        //注册按钮
        @IBOutlet weak var signupOutlet: UIButton!
         
        let disposeBag = DisposeBag()
         
        override func viewDidLoad() {
            super.viewDidLoad()
             
            //初始化ViewModel
            let viewModel = GitHubSignupViewModel(
                input: (
                    username: usernameOutlet.rx.text.orEmpty.asDriver(),
                    password: passwordOutlet.rx.text.orEmpty.asDriver(),
                    repeatedPassword: repeatedPasswordOutlet.rx.text.orEmpty.asDriver(),
                    loginTaps: signupOutlet.rx.tap.asSignal()
                ),
                dependency: (
                    networkService: GitHubNetworkService(),
                    signupService: GitHubSignupService()
                )
            )
             
            //用户名验证结果绑定
            viewModel.validatedUsername
                .drive(usernameValidationOutlet.rx.validationResult)
                .disposed(by: disposeBag)
             
            //密码验证结果绑定
            viewModel.validatedPassword
                .drive(passwordValidationOutlet.rx.validationResult)
                .disposed(by: disposeBag)
             
            //再次输入密码验证结果绑定
            viewModel.validatedPasswordRepeated
                .drive(repeatedPasswordValidationOutlet.rx.validationResult)
                .disposed(by: disposeBag)
             
            //注册按钮是否可用
            viewModel.signupEnabled
                .drive(onNext: { [weak self] valid  in
                    self?.signupOutlet.isEnabled = valid
                    self?.signupOutlet.alpha = valid ? 1.0 : 0.3
                })
                .disposed(by: disposeBag)
             
            //当前是否正在注册
            viewModel.signingIn
                .drive(UIApplication.shared.rx.isNetworkActivityIndicatorVisible)
                .disposed(by: disposeBag)
             
            //注册结果绑定
            viewModel.signupResult
                .drive(onNext: { [unowned self] result in
                    self.showMessage("注册" + (result ? "成功" : "失败") + "!")
                })
                .disposed(by: disposeBag)
        }
         
        //详细提示框
        func showMessage(_ message: String) {
            let alertController = UIAlertController(title: nil,
                                                    message: message, preferredStyle: .alert)
            let okAction = UIAlertAction(title: "确定", style: .cancel, handler: nil)
            alertController.addAction(okAction)
            self.present(alertController, animated: true, completion: nil)
        }
    }
    

    三、UIActivityIndicatorView 的绑定

    1,效果图

    (1)当我们点击注册按钮发起请求时,按钮左侧会显示一个菊花状的网络请求指示器。

    (2)当注册结果返回时,按钮左侧的网络请求指示器消失。

    2,样例代码

    (1)首先打开 StoryBoard,在注册按钮的左侧放置一个 Activity Indicator View,同时设置当其动画停止时自动隐藏,并将其与代码做 @IBOutlet 绑定。

    (2)最后只需要在主视图控制器中将 signingIn 绑定到 Activity Indicator ViewisAnimating 属性上即可。

    import UIKit
    import RxSwift
    import RxCocoa
     
    class ViewController: UIViewController {
        //用户名输入框、以及验证结果显示标签
        @IBOutlet weak var usernameOutlet: UITextField!
        @IBOutlet weak var usernameValidationOutlet: UILabel!
         
        //密码输入框、以及验证结果显示标签
        @IBOutlet weak var passwordOutlet: UITextField!
        @IBOutlet weak var passwordValidationOutlet: UILabel!
         
        //重复密码输入框、以及验证结果显示标签
        @IBOutlet weak var repeatedPasswordOutlet: UITextField!
        @IBOutlet weak var repeatedPasswordValidationOutlet: UILabel!
         
        //注册按钮
        @IBOutlet weak var signupOutlet: UIButton!
         
        //注册时的活动指示器
        @IBOutlet weak var signInActivityIndicator: UIActivityIndicatorView!
         
        let disposeBag = DisposeBag()
         
        override func viewDidLoad() {
            super.viewDidLoad()
             
            //初始化ViewModel
            let viewModel = GitHubSignupViewModel(
                input: (
                    username: usernameOutlet.rx.text.orEmpty.asDriver(),
                    password: passwordOutlet.rx.text.orEmpty.asDriver(),
                    repeatedPassword: repeatedPasswordOutlet.rx.text.orEmpty.asDriver(),
                    loginTaps: signupOutlet.rx.tap.asSignal()
                ),
                dependency: (
                    networkService: GitHubNetworkService(),
                    signupService: GitHubSignupService()
                )
            )
             
            //用户名验证结果绑定
            viewModel.validatedUsername
                .drive(usernameValidationOutlet.rx.validationResult)
                .disposed(by: disposeBag)
             
            //密码验证结果绑定
            viewModel.validatedPassword
                .drive(passwordValidationOutlet.rx.validationResult)
                .disposed(by: disposeBag)
             
            //再次输入密码验证结果绑定
            viewModel.validatedPasswordRepeated
                .drive(repeatedPasswordValidationOutlet.rx.validationResult)
                .disposed(by: disposeBag)
             
            //注册按钮是否可用
            viewModel.signupEnabled
                .drive(onNext: { [weak self] valid  in
                    self?.signupOutlet.isEnabled = valid
                    self?.signupOutlet.alpha = valid ? 1.0 : 0.3
                })
                .disposed(by: disposeBag)
             
            //当前是否正在注册
            viewModel.signingIn
                .drive(signInActivityIndicator.rx.isAnimating)
                .disposed(by: disposeBag)
             
            //注册结果绑定
            viewModel.signupResult
                .drive(onNext: { [unowned self] result in
                    self.showMessage("注册" + (result ? "成功" : "失败") + "!")
                })
                .disposed(by: disposeBag)
        }
         
        //详细提示框
        func showMessage(_ message: String) {
            let alertController = UIAlertController(title: nil,
                                                    message: message, preferredStyle: .alert)
            let okAction = UIAlertAction(title: "确定", style: .cancel, handler: nil)
            alertController.addAction(okAction)
            self.present(alertController, animated: true, completion: nil)
        }
    }
    

    四、第三方指示器的绑定

    这里我以 MBProgressHUD 这个第三方透明指示器为例做演示,关于 MBProgressHUD 相关介绍和配置方法,可以参考这篇文章:

    1,效果图

    (1)当我们点击注册按钮发起请求时,页面中央会显示一个菊花状的网络请求指示器。

    (2)当注册结果返回时,页面中央的网络请求指示器消失。

    2,样例代码

    我们同样地将 signingIn 绑定到指示器地显示隐藏属性上即可。

    import UIKit
    import RxSwift
    import RxCocoa
     
    class ViewController: UIViewController {
        //用户名输入框、以及验证结果显示标签
        @IBOutlet weak var usernameOutlet: UITextField!
        @IBOutlet weak var usernameValidationOutlet: UILabel!
         
        //密码输入框、以及验证结果显示标签
        @IBOutlet weak var passwordOutlet: UITextField!
        @IBOutlet weak var passwordValidationOutlet: UILabel!
         
        //重复密码输入框、以及验证结果显示标签
        @IBOutlet weak var repeatedPasswordOutlet: UITextField!
        @IBOutlet weak var repeatedPasswordValidationOutlet: UILabel!
         
        //注册按钮
        @IBOutlet weak var signupOutlet: UIButton!
         
        let disposeBag = DisposeBag()
         
        override func viewDidLoad() {
            super.viewDidLoad()
             
            //初始化ViewModel
            let viewModel = GitHubSignupViewModel(
                input: (
                    username: usernameOutlet.rx.text.orEmpty.asDriver(),
                    password: passwordOutlet.rx.text.orEmpty.asDriver(),
                    repeatedPassword: repeatedPasswordOutlet.rx.text.orEmpty.asDriver(),
                    loginTaps: signupOutlet.rx.tap.asSignal()
                ),
                dependency: (
                    networkService: GitHubNetworkService(),
                    signupService: GitHubSignupService()
                )
            )
             
            //用户名验证结果绑定
            viewModel.validatedUsername
                .drive(usernameValidationOutlet.rx.validationResult)
                .disposed(by: disposeBag)
             
            //密码验证结果绑定
            viewModel.validatedPassword
                .drive(passwordValidationOutlet.rx.validationResult)
                .disposed(by: disposeBag)
             
            //再次输入密码验证结果绑定
            viewModel.validatedPasswordRepeated
                .drive(repeatedPasswordValidationOutlet.rx.validationResult)
                .disposed(by: disposeBag)
             
            //注册按钮是否可用
            viewModel.signupEnabled
                .drive(onNext: { [weak self] valid  in
                    self?.signupOutlet.isEnabled = valid
                    self?.signupOutlet.alpha = valid ? 1.0 : 0.3
                })
                .disposed(by: disposeBag)
             
            //创建一个指示器
            let hud = MBProgressHUD.showAdded(to: self.view, animated: true)
             
            //当前是否正在注册,决定指示器是否显示
            viewModel.signingIn
                .map{ !$0 }
                .drive(hud.rx.isHidden)
                .disposed(by: disposeBag)
          
            //注册结果绑定
            viewModel.signupResult
                .drive(onNext: { [unowned self] result in
                    self.showMessage("注册" + (result ? "成功" : "失败") + "!")
                })
                .disposed(by: disposeBag)
        }
         
        //详细提示框
        func showMessage(_ message: String) {
            let alertController = UIAlertController(title: nil,
                                                    message: message, preferredStyle: .alert)
            let okAction = UIAlertAction(title: "确定", style: .cancel, handler: nil)
            alertController.addAction(okAction)
            self.present(alertController, animated: true, completion: nil)
        }
    }
    

    RxSwift使用详解系列
    原文出自:www.hangge.com转载请保留原文链接

    相关文章

      网友评论

        本文标题:Swift - RxSwift的使用详解55(一个用户注册样例2

        本文链接:https://www.haomeiwen.com/subject/vromrftx.html