RxSwift+MVVM项目实战-单分组UITableView添加、删除、移动功能

简介: RxSwift+MVVM项目实战-单分组UITableView添加、删除、移动功能

本文主要介绍利用RxSwift+MVVM实现只有一个分组列表的添加、删除、移动功能,实现效果如图(文末附源码):

   

   

EditModel

title:用于cell上展示的标题;

index用于cell上展示的随机数;


class EditModel {
    var title: String?
    var index: Int
    init(title: String?) {
        self.title = title
        self.index = Self.random
    }
    static var random: Int {
        Int(arc4random() % 10000)
    }
}


EditCellViewModel

title:用于将处理后的标题绑定到cellUI控件上;

class EditCellViewModel: NSObject {
    var title = BehaviorRelay<String?>(value: nil)
    init(model: EditModel) {
        self.title.accept("\(model.title ?? "") - 随机数 - \(model.index)")
    }
}

EditTableViewCell

主要是cell内部子控件的布局,以及绑定数据到UI

func bind(to viewModel: EditCellViewModel) {
    if let _label = textLabel {
        viewModel.title.bind(to: _label.rx.text).disposed(by: disposeBag)
    }
}

EditOperationType

存储用于操作的事件类型,并存储数据;

enum EditOperationType {
    case refresh //刷新
    case delete(items: IndexPath) //删除
    case move(event: ItemMovedEvent) //移动
    case add(cellModel: EditCellViewModel) //添加
}


EditViewModel

refresh:接收刷新的事件;

movedtableView移动的事件;

deletetableView的删除事件;

add:添加事件;

input中的各种事件通过map转换为对应的操作类型,并保存数据,通过merge操作对dataSource进行对应的处理,并抛出到外界绑定到tableView的数据源上,以更新数据;

class EditViewModel {
    private let disposeBag = DisposeBag()
    private lazy var dataSource: [EditCellViewModel] = {
        var _items = [EditCellViewModel]()
        for index in 0...5 {
            let a1 = EditModel.random
            _items.append(EditCellViewModel(model: EditModel(title: "初识标题")))
        }
        return _items
    }()
    struct Input {
        let refresh: Observable<Void>
        let moved: ControlEvent<ItemMovedEvent>
        let delete: ControlEvent<IndexPath>
        let add: Observable<Void>
    }
    struct Output {
        let items: BehaviorRelay<[EditCellViewModel]>
    }
    func transform(input: Input) -> Output {
        let dataSource = BehaviorRelay<[EditCellViewModel]>(value: [])
        let refresh = input.refresh.map({ EditOperationType.refresh })
        let delete = input.delete.map({ EditOperationType.delete(items: $0) })
        let move = input.moved.map({ EditOperationType.move(event: $0)})
        let add = input.add.map({ EditOperationType.add(cellModel: EditCellViewModel(model: EditModel(title: "添加标题"))) })
        Observable.of(refresh, delete, move, add).merge().map {[weak self] type -> [EditCellViewModel] in
            guard let `self` = self else { return [] }
            switch type {
            case .delete(let indexPath):
                self.dataSource.remove(at: indexPath.row)
                break
            case .move(let itemMove):
                self.dataSource.insert(self.dataSource.remove(at: itemMove.sourceIndex.row), at: itemMove.destinationIndex.row)
                break
            case .refresh:
                break
            case .add(cellModel: let cellModel):
                self.dataSource.append(cellModel)
                break
            }
            return self.dataSource
        }.bind(to: dataSource).disposed(by: disposeBag)
        return Output(items: dataSource)
    }
}


EditViewController

绑定ViewModel数据,以及监听事件并做出响应;


private func bindToViewModel() {
    let output = viewModel.transform(input: RootViewModel.Input(refresh: Observable.of(()), moved: tableView.rx.itemMoved, delete: tableView.rx.itemDeleted, add: addItem.rx.tap.asObservable()))
    output.items.asDriver().drive(tableView.rx.items(cellIdentifier: cellId, cellType: EditTableViewCell.self)) {row, viewModel, cell in
        cell.bind(to: viewModel)
    }.disposed(by: disposeBag)
    tableView.rx.modelSelected(EditCellViewModel.self).subscribe {[weak self] (cellModel) in
        Logger(cellModel.element?.title.value)
    }.disposed(by: disposeBag)
    tableView.rx.itemSelected.subscribe {[weak tableView] in tableView?.deselectRow(at: $0, animated: true) }.disposed(by: disposeBag)
    editItem.rx.tap.map({[unowned self] in !self.tableView.isEditing }).bind(to: tableView.rx.isCanEditing).disposed(by: disposeBag)
    Observable.of(Observable.just(()), editItem.rx.tap.asObservable()).merge().map({[unowned self] _ in !self.tableView.isEditing }).bind(to: editItem.rx.isCanEditing).disposed(by: disposeBag)
    tableView.rx.setDelegate(self).disposed(by: disposeBag)
}


复制搜一搜分享收藏划线


相关文章
|
Java 应用服务中间件 开发工具
最简单JDK安装指南(小白也能一次性安装完成)
最简单JDK安装指南(小白也能一次性安装完成)
|
Dart 开发工具 Android开发
如何验证Flutter环境配置是否成功?
如何验证Flutter环境配置是否成功?
1433 164
|
安全 Java 数据安全/隐私保护
SpringSecurity6从入门到实战之引言和基本概念
《SpringSecurity6从入门到实战》介绍了Spring Security这一强大的Java安全框架,主要用于保护Spring应用程序的安全。它提供认证和授权功能,支持多种认证方式,并具备高度可定制性。文章阐述了权限管理的重要性,包括用户认证(验证用户身份)和用户授权(控制用户访问权限)。相较于其他如Shiro和Sa-Token的安全框架,Spring Security因与Spring生态的深度整合及对OAuth2的支持,常成为微服务项目的选择。
|
JavaScript
Vue3基础(20)___Vue3配置错误路由重定向写法
本文介绍了Vue 3中配置错误路由重定向的正确写法,包括使用参数和自定义正则表达式来定义通配符路由。
338 0
Vue3基础(20)___Vue3配置错误路由重定向写法
【Flutter】状态管理:Provider状态管理
【Flutter】状态管理:Provider状态管理
658 0
|
iOS开发
如何找到Xcode中下载的Provisioning Profile文件
如何找到Xcode中下载的Provisioning Profile文件
2589 1
|
存储 算法 安全
|
存储 Swift
RxSwift+MVVM项目实战-多分组UITableView结合RxDataSources的使用
RxSwift+MVVM项目实战-多分组UITableView结合RxDataSources的使用
770 0
|
算法 编译器 Swift
【Swift开发专栏】Swift与Objective-C的对比
【4月更文挑战第30天】Swift与Objective-C对比:Swift语法简洁,支持元组、泛型和闭包,提高可读性;性能优化,使用LLVM编译器,与Objective-C兼容,便于迁移项目;生态系统活跃,苹果官方支持,丰富资源库。Objective-C虽历史悠久,但逐渐边缘化。对于新项目和开发者,Swift是更佳选择,驱动iOS开发创新。
1320 0
|
自然语言处理 前端开发
深入解析 React-i18next:在 React 中实现国际化(二)
深入解析 React-i18next:在 React 中实现国际化(二)
501 0