持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天,点击查看活动详情
前言
又来撸RXSwift了
如果您还没有阅读上一部分,它可以在这里找到。在上一篇中,我们实现了如何设置只有一种cell的 TableView。
在本文中,我们将实现如何设置具有一个section,多种cell的tableview
那么就需要引入一个新的库
pod RxDataSources
这个库可以帮我们实现更多功能,使用它可以大大减少我们的工作量。更多功能可以自行百度。
正文
项目的目录结构还是一样。
第一步 定义Model
咱们在Model文件夹中创建两个文件 Student.swift和 Teacher.swift 分别对应两个模型
import Foundation
struct Student {
let name : String
let lastName : String
}
import Foundation
struct Teacher {
let name : String
let lastName : String
let major : String
}
第二步 视图模型(viewModel)
在ViewModel文件夹下新建StudentViewModel 然后导入
import RxDataSources
然后定义一个section 使用enum
enum TableViewSection {
case main
}
定义一个item
enum TableViewItem {
case student(info: Student)
case teacher(info: Teacher)
}
然后定义一个SectionOfStudent
typealias SectionOfStudent = SectionModel<TableViewSection,TableViewItem>
这里的SectionModel是来自RxDataSources,它有两个参数,一个是Section,另一个是Item,咱们就用上面定义好的TableViewSection 和 TableViewItem传入
所以,SectionOfStudent 就相当于一个section里的所有内容了,初始化它也十分简单
SectionOfStudent(model: .main, items: subItems)
这里的.main 也可以只是个枚举,可以自定义为别的,也可以传空。
subItems就一个数组,里面就是需要传入的数据模型。
接下来 我们在进行模拟数据请求
class StudentViewModel {
let items = PublishSubject<[SectionOfStudent]>()
// 模拟请求
func getInformation() {
// 定义一个数组模型
var subItems = [TableViewItem]()
subItems = ([
.student(info: Student(name: "Liam", lastName: "swift")),
.teacher(info: Teacher(name: "Emma", lastName: "Das", major: "Math")),
.student(info: Student(name: "Ava", lastName: "Banks")),
.teacher(info: Teacher(name: "Bill", lastName: "Cooper", major: "Math")),
.student(info: Student(name: "Caden", lastName: "Smith")),
.teacher(info: Teacher(name: "Isabella", lastName: "Watson", major: "Math")),
])
// 发送数据
items.onNext([SectionOfStudent(model: .main, items: subItems)])
}
}
这样,咱们就完成了一个,只有一个section,和多个cell的数据
第三步 视图(View)
咱们在View文件夹下创建一个StudentViewController
同样的设置 bag 和 viewModel
private let bag = DisposeBag()
private let viewModel = StudentViewModel()
然后设置两个懒加载变量 ConfigureCell 和 dataSource
private lazy var dataSource = RxTableViewSectionedReloadDataSource<SectionOfStudent>(configureCell: configureCell)
private lazy var configureCell: RxTableViewSectionedReloadDataSource<SectionOfStudent>.ConfigureCell = { [unowned self] (dataSource, tableView, indexPath, item) in
switch item {
case .student(let info):
return self.configStudentCell(student: info, atIndex: indexPath)
case .teacher(let info):
return self.configTeacherCell(teacher: info, atIndex: indexPath)
}
}
configureCell 是一个闭包cell 通过传入的item来返回不同的cell
dataSource 接收一个 ConfigureCell 类型作为参数,所以我们将 ConfigureCell 实例传递给 dataSource 并 将数据直接绑定到 TableView。
接下来我们在viewDidLoad中可以做一些绑定操作了
override func viewDidLoad() {
super.viewDidLoad()
tableView.rx.setDelegate(self).disposed(by: bag)
tableView.register(UINib(nibName: "StudentCell", bundle: nil), forCellReuseIdentifier: "StudentTableViewCell")
tableView.register(UINib(nibName: "TeacherCell", bundle: nil), forCellReuseIdentifier: "TeacherTableViewCell")
viewModel.items
.bind(to: tableView.rx.items(dataSource: dataSource))
.disposed(by: bag)
viewModel.getInformation()
}
这里的 StudentCell 和 TeacherCell都是自定义的,可以自行处理。
viewModel.getInformation() 表示开始请求数据(当然这里是假数据)
最后再写两个创建cell的函数
func configStudentCell(student: Student, atIndex: IndexPath) -> UITableViewCell {
guard let cell = self.tableView.dequeueReusableCell(withIdentifier: "StudentCell", for: atIndex) as? StudentCell else {
return UITableViewCell()
}
cell.viewModel = student
return cell
}
func configTeacherCell(teacher: Teacher, atIndex: IndexPath) -> UITableViewCell {
guard let cell = self.tableView.dequeueReusableCell(withIdentifier: "TeacherCell", for: atIndex) as? TeacherCell else {
return UITableViewCell()
}
cell.viewModel = teacher
return cell
}
和UITableViewDelegate
extension StudentViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 150
}
}
就基本上完成了
可以看看效果图
结语
总体来说 使用RxDataSources来进行tableview的处理,难度又上升了,里面又涉及到许多新的函数和变量需要理解,不过理解后处理起来就方便许多,代码量也少了。