我是RxSwift的新手,并试图通过创建简单的注册表单来学习。我想使用来实现它UITableView
(作为练习,加上将来它将变得更加复杂),因此我目前正在使用两种类型的单元格:
TextInputTableViewCell
只有一个UITextField
ButtonTableViewCell
只有一个UIButton
为了表示每个单元格,我创建了一个如下所示的枚举:
enum FormElement {
case textInput(placeholder: String, text: String?)
case button(title: String, enabled: Bool)
}
并在中使用它Variable
来填充tableview:
formElementsVariable = Variable<[FormElement]>([
.textInput(placeholder: "username", text: nil),
.textInput(placeholder: "password", text: nil),
.textInput(placeholder: "password, again", text: nil),
.button(title: "create account", enabled: false)
])
通过这样的绑定:
formElementsVariable.asObservable()
.bind(to: tableView.rx.items) {
(tableView: UITableView, index: Int, element: FormElement) in
let indexPath = IndexPath(row: index, section: 0)
switch element {
case .textInput(let placeholder, let defaultText):
let cell = tableView.dequeueReusableCell(withIdentifier: "TextInputTableViewCell", for: indexPath) as! TextInputTableViewCell
cell.textField.placeholder = placeholder
cell.textField.text = defaultText
return cell
case .button(let title, let enabled):
let cell = tableView.dequeueReusableCell(withIdentifier: "ButtonTableViewCell", for: indexPath) as! ButtonTableViewCell
cell.button.setTitle(title, for: .normal)
cell.button.isEnabled = enabled
return cell
}
}.disposed(by: disposeBag)
到目前为止,一切都很好-这是我的表格的样子:
现在,我在这里面临的实际问题是,当所有3个文本输入都不为空并且两个密码文本字段中的密码相同时,如何启用创建帐户按钮?换句话说,基于一个或多个其他单元上发生的事件,将更改应用于单元的正确方法是什么?
我的目标应该是formElementsVariable
通过ViewModel进行更改,还是有更好的方法来实现我想要的目标?
我建议您对ViewModel进行一些更改,以便可以更好地控制文本字段中的更改。如果您从用户名,密码和确认之类的输入字段创建流,则可以订阅更改并以所需的任何方式对其做出反应。
这是我为重组文本字段而使用的代码的方式。
internal enum FormElement {
case textInput(placeholder: String, variable: Variable<String>)
case button(title: String)
}
ViewModel。
internal class ViewModel {
let username = Variable("")
let password = Variable("")
let confirmation = Variable("")
lazy var formElementsVariable: Driver<[FormElement]> = {
return Observable<[FormElement]>.of([.textInput(placeholder: "username",
variable: username),
.textInput(placeholder: "password",
variable: password),
.textInput(placeholder: "password, again",
variable: confirmation),
.button(title: "create account")])
.asDriver(onErrorJustReturn: [])
}()
lazy var isFormValid: Driver<Bool> = {
let usernameObservable = username.asObservable()
let passwordObservable = password.asObservable()
let confirmationObservable = confirmation.asObservable()
return Observable.combineLatest(usernameObservable,
passwordObservable,
confirmationObservable) { [unowned self] username, password, confirmation in
return self.validateFields(username: username,
password: password,
confirmation: confirmation)
}.asDriver(onErrorJustReturn: false)
}()
fileprivate func validateFields(username: String,
password: String,
confirmation: String) -> Bool {
guard username.count > 0,
password.count > 0,
password == confirmation else {
return false
}
// do other validations here
return true
}
}
ViewController,
internal class ViewController: UIViewController {
@IBOutlet var tableView: UITableView!
fileprivate var viewModel = ViewModel()
fileprivate let disposeBag = DisposeBag()
override func viewDidLoad() {
super.viewDidLoad()
viewModel.formElementsVariable.drive(tableView.rx.items) { [unowned self] (tableView: UITableView, index: Int, element: FormElement) in
let indexPath = IndexPath(row: index, section: 0)
switch element {
case .textInput(let placeholder, let variable):
let cell = self.createTextInputCell(at: indexPath,
placeholder: placeholder)
cell.textField.text = variable.value
cell.textField.rx.text.orEmpty
.bind(to: variable)
.disposed(by: cell.disposeBag)
return cell
case .button(let title):
let cell = self.createButtonCell(at: indexPath,
title: title)
self.viewModel.isFormValid.drive(cell.button.rx.isEnabled)
.disposed(by: cell.disposeBag)
return cell
}
}.disposed(by: disposeBag)
}
fileprivate func createTextInputCell(at indexPath:IndexPath,
placeholder: String) -> TextInputTableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TextInputTableViewCell",
for: indexPath) as! TextInputTableViewCell
cell.textField.placeholder = placeholder
return cell
}
fileprivate func createButtonCell(at indexPath:IndexPath,
title: String) -> ButtonInputTableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ButtonInputTableViewCell",
for: indexPath) as! ButtonInputTableViewCell
cell.button.setTitle(title, for: .normal)
return cell
}
}
我们基于三个不同的变量来启用禁用按钮,您可以在此处看到stream和rx运算符的功能。
我认为在我们的情况下,将普通属性更改为用户名,密码和passwordField时,将普通属性转换为Rx总是很好。您可以看到formElementsVariable并没有太大变化,除了用于创建单元格的神奇tableview绑定之外,它没有Rx的真正附加值。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句