如果`UITextField`中的文本有效,如何创建`RxAction`来启用/禁用按钮?

时间:2018-05-08 11:18:30

标签: swift rx-swift

我有多个textFields,他们的验证标准非常简单。

为了简化问题陈述,我们假设标准是

  

名字至少应包含一个字符,
    姓氏应至少有一个字符
    和年龄应该大于0

假设我有一个验证器操作

   validatorAction = Action<Void,Bool> {
        return Single<Bool>.create(subscribe: { (single) -> Disposable in
            if self.firstName.text?.count ?? 0 > 0 && self.lastName.text?.count ?? 0 > 0 && self.age.text?.count ?? 0 > 0 {
                single(.success(true))
            }
            else {
                single(.success(false))
            }
            return Disposables.create()
        })
   }

我希望每次在任何文本字段中的字符更改时执行此操作,因此我将此操作绑定到UIControlEvents.editingChanged

    self.firstName.rx.bind(to: validatorAction, controlEvent: self.firstName.rx.controlEvent(UIControlEvents.editingChanged)){ (textField) -> Void in
        return Void()
    }

    self.lastName.rx.bind(to: validatorAction, controlEvent: self.lastName.rx.controlEvent(UIControlEvents.editingChanged)){ (textField) -> Void in
        return Void()
    }

    self.age.rx.bind(to: validatorAction, controlEvent: self.age.rx.controlEvent(UIControlEvents.editingChanged)) { (textField) -> Void in
        return Void()
    }

最后,我希望操作控制按钮的启用和禁用状态

        validatorAction.elements
        .asObservable()
        .startWith(false)
        .asDriver(onErrorJustReturn: false)
        .drive(self.submitButton.rx.isEnabled)
        .disposed(by: self.disposeBag)

不幸的是,尽管代码工作正常,但每次执行validatorAction时,textField都会失去焦点。这会导致巨大的用户体验问题。

我向RxAction仓库提出issue并获得了回复

  你好!听起来你有点滥用封闭性   传递给Action初始化器。您将尝试使用完整版   初始化程序Action(enabledIf:,workFactory :)分离出一个   用于启用/禁用操作的闭包,以及另一个用于返回的闭包   无论你想做什么工作都可以观察到。然后你可以绑定   对按钮的操作,它将处理启用/禁用它。   查看自述文件以获取更多信息,并告诉我们它是如何进行的。

但是关于如何使用它并没有太大的帮助。有人可以展示如何使用Actions来实现预期行为的具体代码。

1 个答案:

答案 0 :(得分:2)

在我看来,更好的方法是使用文本字段绑定变量并对变量进行验证。

var firstName = Variable<String>("")
var lastName = Variable<String>("")
var age = Variable<String>("")

tfFirstName.rx.text.orEmpty.bind(to: firstName).disposed(by: rx_disposeBag)
tfLastName.rx.text.orEmpty.bind(to: lastName).disposed(by: rx_disposeBag)
tfAge.rx.text.orEmpty.bind(to: age).disposed(by: rx_disposeBag)

然后你可以这样做验证:

var isValid : Observable<Bool>{
    return Observable.combineLatest( firstName.asObservable(), lastName.asObservable(), age.asObservable()){ (fname, lname, userAge) in
        return fname.count > 0 && lname.count > 0 && userAge.count > 0
    }
}

最后,您可以像这样绑定Action submitButton:

submitButton.rx.action = Action(enabledIf: isValid, workFactory:{input in
    //Action code here
})

我希望能回答你的问题。