如何使用MVVM / RxSwift根据其他单元格的值更新表视图的单元格?

phi

我是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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何通过VBA根据其他单元格值更改单元格的背景颜色

其他单元格值更改时如何将单元格值更新为“”?

如何在Excel中制作一个单元格以根据其他单元格的值更改颜色?

数据表...如何根据表的单元格值更改单元格的颜色

如何根据单元格值更改php中的单元格表颜色?

React:如何根据React表中的单元格值更改表单元格背景

如何根据其他单元格的范围向单元格输入值

如何根据位置可变的其他单元格设置单元格值

如何根据其他单元格中的日期汇总单元格?

如何根据其他单元格值突出显示单元格

如何根据其他单元格值使单元格可编辑

如何引用其他工作表中的单元格

如何根据单元格值将数据复制到其他工作表

如何根据条件获取其他工作表中的单元格值?

如何根据其值更改R Shiny数据表的单元格的单元格颜色?

如何使用python根据同一csv文件中的其他列单元格更新列单元格中的值?

如何根据单元格的值更改单元格的多种格式参数?

如何根据单元格值更改wpf Databound网格单元格?

如何根据其他单元格中的值禁用(只读)DataGridView CheckBox列中的单元格?

如何通过在其他单元格或工作表中输入值来重复更改单元格值?

如何根据值更改HTML表(动态创建)单元格的颜色?

如何根据值更改ANTD表中的单元格颜色?

使用vba根据行值更新列中的相应单元格

使用PHPExcel添加新行时,如何保持来自其他工作表的单元格引用的更新

单击行中的其他单元格时如何从单元格中获取值?

当其他单元格重新排序时,如何使UICollectionView单元格忽略位置更改?

使用其他单元格中的值引用Excel中的单元格

Excel如果空白单元格在公式中使用其他单元格

使用其他单元格的值对Microsoft Excel单元格进行着色