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)
}


复制搜一搜分享收藏划线


相关文章
|
3月前
|
开发框架 缓存 前端开发
循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(11) -- 下拉列表的数据绑定以及自定义系统字典列表控件
循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(11) -- 下拉列表的数据绑定以及自定义系统字典列表控件
|
3月前
|
C# 前端开发 UED
WPF数据验证实战:内置控件与自定义规则,带你玩转前端数据验证,让你的应用程序更上一层楼!
【8月更文挑战第31天】在WPF应用开发中,数据验证是确保输入正确性的关键环节。前端验证能及时发现错误,提升用户体验和程序可靠性。本文对比了几种常用的WPF数据验证方法,并通过示例展示了如何使用内置验证控件(如`TextBox`)及自定义验证规则实现有效验证。内置控件结合`Validation`类可快速实现简单验证;自定义规则则提供了更灵活的复杂逻辑支持。希望本文能帮助开发者更好地进行WPF数据验证。
118 0
|
存储 数据安全/隐私保护
RxSwift+MVVM项目实战-登录功能实现
RxSwift+MVVM项目实战-登录功能实现
255 0
|
6月前
|
JavaScript 小程序 Android开发
【经验分享】如何实现自定义的actionSheet组件
【经验分享】如何实现自定义的actionSheet组件
123 6
RxSwift+MVVM项目实战-单分组UITableView的使用
RxSwift+MVVM项目实战-单分组UITableView的使用
250 0
|
存储 Swift
RxSwift+MVVM项目实战-多分组UITableView结合RxDataSources的使用
RxSwift+MVVM项目实战-多分组UITableView结合RxDataSources的使用
332 0
RxSwift+MVVM项目实战-多分组UITableView+RxDataSources+MJRefresh的使用
RxSwift+MVVM项目实战-多分组UITableView+RxDataSources+MJRefresh的使用
148 0
|
JSON HandyJSON Swift
RxSwift+MVVM项目实战-多分组TableView+MJRefresh+RxAlamofire+HandyJSON的使用
RxSwift+MVVM项目实战-多分组TableView+MJRefresh+RxAlamofire+HandyJSON的使用
334 0
|
前端开发
前端学习笔记202305学习笔记第二十三天-树形控件和路由分析
前端学习笔记202305学习笔记第二十三天-树形控件和路由分析
39 0
|
前端开发
前端学习笔记202305学习笔记第二十三天-树形控件和路由分析2
前端学习笔记202305学习笔记第二十三天-树形控件和路由分析2
60 0