Swift - RxSwift的使用详解34(UITableView的使用5:可编辑表格)
八、可编辑表格
1,效果图
(1)程序启动后表格会自动加载 5 条随机数据。点击“刷新”按钮则又重新生成 5 条数据并显示。
(2)点击“加号”图标后,会在当前数据集的末尾添加一条随机数据并显示。
(3)点击单元格左侧的“减号”图标则可以将该行数据删除。
(4)拖动单元格右侧的控制图标可以改变显示顺序。
2,样例代码
(1)由于编辑操作比较多,我们首先使用 enum 创建一个命令枚举,里面定义了对 tableView 数据的各种操作。//定义各种操作命令 enum TableEditingCommand { case setItems(items: [String]) //设置表格数据 case addItem(item: String) //新增数据 case moveItem(from: IndexPath, to: IndexPath) //移动数据 case deleteItem(IndexPath) //删除数据 }
(2)接着定义 tableView 对应的 ViewModel。这里面除了保存有表格数据外,还包含上面定义的 4 个操作命令的具体实现。
//定义表格对应的ViewModel struct TableViewModel { //表格数据项 fileprivate var items:[String] init(items: [String] = []) { self.items = items } //执行相应的命令,并返回最终的结果 func execute(command: TableEditingCommand) -> TableViewModel { switch command { case .setItems(let items): print("设置表格数据。") return TableViewModel(items: items) case .addItem(let item): print("新增数据项。") var items = self.items items.append(item) return TableViewModel(items: items) case .moveItem(let from, let to): print("移动数据项。") var items = self.items items.insert(items.remove(at: from.row), at: to.row) return TableViewModel(items: items) case .deleteItem(let indexPath): print("删除数据项。") var items = self.items items.remove(at: indexPath.row) return TableViewModel(items: items) } } }
(3)最后便是主视图控制器代码。
import UIKit import RxSwift import RxCocoa import RxDataSources class ViewController: UIViewController { //刷新按钮 @IBOutlet weak var refreshButton: UIBarButtonItem! //新增按钮 @IBOutlet weak var addButton: UIBarButtonItem! //表格 var tableView:UITableView! let disposeBag = DisposeBag() override func viewDidLoad() { super.viewDidLoad() //创建表格视图 self.tableView = UITableView(frame: self.view.frame, style:.plain) //创建一个重用的单元格 self.tableView!.register(UITableViewCell.self, forCellReuseIdentifier: "Cell") self.view.addSubview(self.tableView!) //表格模型 let initialVM = TableViewModel() //刷新数据命令 let refreshCommand = refreshButton.rx.tap.asObservable() .startWith(()) //加这个为了页面初始化时会自动加载一次数据 .flatMapLatest(getRandomResult) .map(TableEditingCommand.setItems) //新增条目命令 let addCommand = addButton.rx.tap.asObservable() .map{ "\(arc4random())" } .map(TableEditingCommand.addItem) //移动位置命令 let movedCommand = tableView.rx.itemMoved .map(TableEditingCommand.moveItem) //删除条目命令 let deleteCommand = tableView.rx.itemDeleted.asObservable() .map(TableEditingCommand.deleteItem) //绑定单元格数据 Observable.of(refreshCommand, addCommand, movedCommand, deleteCommand) .merge() .scan(initialVM) { (vm: TableViewModel, command: TableEditingCommand) -> TableViewModel in return vm.execute(command: command) } .startWith(initialVM) .map { [AnimatableSectionModel(model: "", items: $0.items)] } .share(replay: 1) .bind(to: tableView.rx.items(dataSource: ViewController.dataSource())) .disposed(by: disposeBag) } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) tableView.setEditing(true, animated: true) } //获取随机数据 func getRandomResult() -> Observable<[String]> { print("生成随机数据。") let items = (0 ..< 5).map {_ in "\(arc4random())" } return Observable.just(items) } } extension ViewController { //创建表格数据源 static func dataSource() -> RxTableViewSectionedAnimatedDataSource <AnimatableSectionModel<String, String>> { return RxTableViewSectionedAnimatedDataSource( //设置插入、删除、移动单元格的动画效果 animationConfiguration: AnimationConfiguration(insertAnimation: .top, reloadAnimation: .fade, deleteAnimation: .left), configureCell: { (dataSource, tv, indexPath, element) in let cell = tv.dequeueReusableCell(withIdentifier: "Cell")! cell.textLabel?.text = "条目\(indexPath.row):\(element)" return cell }, canEditRowAtIndexPath: { _, _ in return true //单元格可删除 }, canMoveRowAtIndexPath: { _, _ in return true //单元格可移动 } ) } }