iOS 上基于 RxSwift 的动态表单填写

SwiftGG 成员, 沙龙负责人,GMTC iDev 讲师,目前致力于推广 RxSwift。

文章正文

在前端表单填写无处不在,但在 iOS 上,这件事并没有那么轻松,主要是因为我们需要 UITableViewUICollectionView 展示一项一项的数据。

UITableViewUICollectionView 的 API 不像写一个 HTML ,需要什么就直接写什么,你可以从 HTML 上直接明白这大概是怎么样的一个表单。但在 iOS 上,我们会写一大堆的返回 Cell 的逻辑。在更新 UI 的时候,也不像 HTML 那么轻松,直接更新对应的 DOM 即可。但由于 Cell 的重用,我们不能很好地找到对应的 “DOM” 。而完整的表单还涉及到表单验证问题,这进一步增加了在 iOS 表单提交的难度。

本文我们将关注改进当前表单填写的体验和代码上的优化。此外我们还会关注表单的组合关系:

  • 改进填写体验

  • 复杂表单填写

  • 表单验证

  • 表单组合

示例代码地址:https://github.com/DianQK/gitchat-form

改进填写体验

这是一个非常简单的表单:

选择多个用户,并提交。

选择多个用户

体验一下 TIM (腾讯出品的办公版 QQ)这个选择用户的交互,你可以感受到点击到 Cell 的反馈不够流畅。这里值得思考一下:

我们是否需要刷新视图? 是。 我们是否可以通过 reload 刷新 Cell ? 是。 我们是否必须通过 reload 刷新 Cell ? 不是,我们可以直接拿到这个 Cell ,直接更新 Cell 上的 UI 。

那我们想办法完成这个效果。我们要做两件事情:

  • 如果当前 Cell 在屏幕中,更新 Cell 为我们的预期样式。

  • 更新对应的 Model.

为此我们只需要为 Model 添加绑定功能,Model 值的变化将直接更新 Cell 上的内容。

我们可以为每个对应于 Cell 的 Model 创建添加一个 isSelected 属性,代码如下所示:

    struct Item {
        let name: String
        let isSelected: Variable<Bool>
    }

接下来我们则只需要将 isSelected 状态绑定到 Cell 的视图变化中:

    Driver.just((1...9).map { Item(name: "\($0)", isSelected: Variable<Bool>(false)) })
        .drive(tableView.rx.items(cellIdentifier: "Cell", cellType: ReactiveTableViewCell.self)) { row, item, cell in
            cell.textLabel?.text = item.name
            item.isSelected.asDriver()
                .map { isSelected -> UITableViewCellAccessoryType in
                    if isSelected {
                        return UITableViewCellAccessoryType.checkmark
                    } else {
                        return UITableViewCellAccessoryType.none
                    }
                }
                .drive(cell.rx.accessoryType)
                .disposed(by: cell.reuseDisposeBag)
        }
        .disposed(by: disposeBag)

我们将每个 Model 的属性 isSelected 通过 map 方法绑定到 Cell 的 accessoryType 属性上。

通过 reuseDisposeBag ,我们无需担心 Cell 重用问题:

    open class ReactiveTableViewCell: UITableViewCell {

        public private(set) var reuseDisposeBag = DisposeBag()

        open override func prepareForReuse() {
            super.pr
                        
作者正在撰写中...
隐藏内容 支付可见
内容互动
写评论
加载更多
评论文章
¥10 购买
× 订阅 Java 精选频道
¥ 元/月
订阅即可免费阅读所有精选内容