美文网首页
RxSwift UI交互 - I

RxSwift UI交互 - I

作者: 醉看红尘这场梦 | 来源:发表于2021-04-06 09:43 被阅读0次

    了解了RxSwift的基本概念和用法之后,我们通过一系列视频向大家介绍如何用RxSwift处理UI交互。在这个例子里,我们实现一个简单的登录UI,对比传统的delegate方式,我们将看到RxSwift在处理异步事件时的简洁和便利。

    准备工作

    下载项目初始模板。

    首先,我们创建了一个Single View Application,并且安装好了RxSwift。在Main.storyboard里,我们添加两个UITextFile用于输入邮箱和密码,以及一个UIButton表示注册。

    image

    并且,我们在ViewController里,添加了对应的IBOutlet,以及一个用于回收Disposable对象的DisposeBag

    class ViewController: UIViewController {
    
        @IBOutlet weak var email: UITextField!
        @IBOutlet weak var password: UITextField!
        @IBOutlet weak var register: UIButton!
    
        var bag: DisposeBag! = DisposeBag()
    
    }
    
    

    除此之外,我们还添加了一个辅助类InputValidator,它有两个类方法:

    • isValidEmail(email: String)用于验证email是否是一个合法的电子邮件:
    class func isValidEmail(email: String) -> Bool {
        let re = try? NSRegularExpression(
            pattern: "^\\S+@\\S+\\.\\S+$",
            options: .CaseInsensitive)
    
        if let re = re {
            let range = NSMakeRange(0, 
                email.lengthOfBytesUsingEncoding(
                NSUTF8StringEncoding))
    
            let result = re.matchesInString(email,
                options: .ReportProgress,
                range: range)
    
            return result.count > 0
        }
    
        return false
    }
    
    
    • isValidPassword(password: String)用于验证密码的长度是否大于等于8;
    class func isValidPassword(
        password: String) -> Bool {
        return password.characters.count >= 8
    }
    
    

    至此,所有的准备工作就结束了,接下来,我们来处理用户交互。


    让输入框内容合法时变成绿色

    先来处理Email的输入。

    之前我们也提到过,RxSwift给UITextField添加了一个扩展rx_text,表示输入事件序列,而事件的值,是每一次输入后,UITextField中的字符串。因此,我们可以先使用map把字符串变成一个Bool,表示当前UITextField中的值是否是一个合法的电子邮件。

    viewDidLoad方法里,添加下面的代码:

    let emailObservable = 
        self.email.rx_text.map { 
            (input: String) -> Bool in
                return InputValidator.isValidEmail(input)
        }
    
    

    然后,我们希望当内容为合法的Email时,给UITextField添加一个绿色的边框,因此,我们还要进一步把Observable<Bool>变成一个Observable<UIColor>

    emailObservable.map { (valid: Bool) -> UIColor in
        let color = valid ? 
            UIColor.greenColor() : UIColor.clearColor()
    
        return color
    }
    
    

    这样,我们就可以使用subscribeNext订阅这个事件了:

    emailObservable.map { (valid: Bool) -> UIColor in
            let color = valid ? 
                UIColor.greenColor() : UIColor.clearColor()
    
            return color
        }.subscribeNext({
            self.email.layer.borderColor = $0.CGColor
        }).addDisposableTo(self.bag)
    
    

    这反而是最简单的一步,我们直接把.Next的associated value赋值给self.email.layer.borderColor属性就可以了。

    最后,为了能看到这个绿色的边框,我们在viewDidLoad开始要设置一下边框的宽度:

    self.email.layer.borderWidth = 1
    
    

    这样,按Command + R编译执行,当我们输入一个完整的email后,就可以看到Email输入框变为绿色了:

    image

    接下来,我们可以用同样的方式处理password输入框,过程就不细说了,只是贴上代码:

    let passwordObservable = 
        self.password.rx_text.map { 
            (input: String) -> Bool in
                return InputValidator.isValidPassword(input)
        }
    
    passwordObservable.map { 
        (valid: Bool) -> UIColor in
            let color = valid ? 
                UIColor.greenColor() : UIColor.clearColor()
    
            return color
        }.subscribeNext({
            self.password.layer.borderColor = $0.CGColor
        }).addDisposableTo(self.bag)
    
    

    最后,不要忘记在viewDidLoad开始,也设置password输入框边框的宽度:

    self.password.layer.borderWidth = 1
    
    

    然后,Command + R编译执行,当我们在密码框中输入长度大于等于8的密码后,password输入框就变成绿色了:

    image

    这就是UITextField在RxSwift中的用法,简单来说,就是利用输入的字符串,把rx_text变换成我们需要的事件逻辑,然后订阅对应的事件进行操作就可以了

    接下来,我们要实现另外一个效果:我们希望只有当Email和Password中的输入都合法时,才启用Sign Up按钮,否则禁用它,该怎么做呢?


    禁用和启用UIButton

    在我们的例子里,emailObservablepasswordObservable是两个独立的事件序列。如果我们要表达“它们的输入都合法”这样的语义,也就是说,这两个事件序列中最新的事件值都是合法的

    为此,RxSwift提供了一个专门的operator,叫做combineLatest,它用于将多个事件序列中最新的事件进行合并。我们可以在这里找到combineLatest的详细定义。

    至此,我们就有思路了。只要将emailObservablepasswordObservable中最新的事件进行合并,如果它们都是true,就启用Sign Up按钮,否则就禁用。

    有了思路之后,就可以开工了。继续在viewDidLoad里,添加下面的代码:

    Observable.combineLatest(
        emailObservable, passwordObservable) {
        (validEmail: Bool, validPassword: Bool) -> [Bool] in
        return [validEmail, validPassword]
    }
    
    

    combineLatest的前两个参数表示要合并的事件序列,第三个参数是一个closure,表示合并的方法,在我们的例子里,我们把emailObservable和passwordObservable中的两个最新事件的Bool,变成了一个Bool数组。

    接下来,我们使用map把合并的结果变成一个单一的Observable<Bool>

    Observable.combineLatest(
        emailObservable, passwordObservable) {
            (validEmail: Bool, validPassword: Bool) -> [Bool] in
                return [validEmail, validPassword]
        }
        .map { (input: [Bool]) -> Bool in
            let validValues = input.reduce(true, 
                combine: { $0 && $1 })
    
            return validValues
        }
    
    

    这样,我们就得到了一个Observable<Bool>,我们订阅它,然后设置按钮的状态就可以了:

    Observable.combineLatest(
        emailObservable, passwordObservable) {
            (validEmail: Bool, validPassword: Bool) -> [Bool] in
                return [validEmail, validPassword]
        }
        .map { (input: [Bool]) -> Bool in
           let validValues = input.reduce(true, 
               combine: { $0 && $1 })
    
           return validValues
        }
        .subscribeNext { (isEnabled: Bool) in
            self.register.enabled = isEnabled
        }.addDisposableTo(self.bag)
    
    

    然后,按Command + R编译执行,就可以看到只有当Email和Password都输入正确后,Sign Up按钮才会被启用的效果了。

    image

    相关文章

      网友评论

          本文标题:RxSwift UI交互 - I

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