SwiftDataProvider
示例
对于 TableViews 和动画更新的模板代码已不再需要。现在您可以设计带有 Models 的 TableView,而不是追踪所有 IndexPaths 和 IndexSets,简单方便。
要运行示例项目,首先克隆源码库,然后在 Example 目录中运行 pod install
要求
iOS 8.0 XCode 10.2 Swift 5.0
安装
SwiftDataProvider 通过 CocoaPods 提供使用。要安装,只需将以下行添加到您的 Podfile 中
pod 'SwiftDataProvider'
作者
Martin Eberl, [email protected]
许可证
SwiftDataProvider遵循MIT许可证。有关更多信息,请参阅LICENSE文件。
用法
1) 实现UIKit中的UITableViewController或UITableView并遵循RecyclerView协议
2) 保持对SwiftDataProvider的强引用
private var swiftDataProvider: SwiftDataProvider?
3) 创建SwiftDataProvider实例(例如在viewDidLoad中)并将其分配为UITableView的UITableViewDataSource
override func viewDidLoad() {
super.viewDidLoad()
//do assign to the tableviews delegate ALWAY BEFORE creating and assigning
//the SwiftDataProvider to the UITableView or UITableViewController, otherwhise
//the section header and footer view won't appear, when you handle them within the SwiftDataProvider
self.tableViewDelegate = self
self.swiftDataProvider = SwiftDataProvider(recyclerView: self)
//step 4
}
4) 注册单元格以实现复用并映射到所需内容,例如以下初始化SwiftDataProvider后。请确保为您的数据模型使用唯一的名称!
swiftDataProvider?.register(cell: UITableViewCell.self, for: String.self) { cell, content in
cell.textLabel?.text = content
}
swiftDataProvider?.register(cell: UITableViewCell.self, for: /*Your data model*/.self) { cell, content in
cell.textLabel?.text = content.formattedDate
}
swiftDataProvider?.register(cellReuseIdentifier: "TestCell", as: TestCell.self, for: TestCell.Content.self) { cell, content in
cell.content = content
}
//step 5
MVVM 模式,但您也可以在 ViewController 中实现 ContentAdapter。
5) 分配内容适配器。示例中使用的是 swiftDataProvider?.contentAdapter = viewModel.contentAdapter
6) a) 使用 ContentProviderAdapter 以自我控制内容并添加部分和行或更新部分标题和页脚
// in the ViewModel
struct ViewModel {
let contentAdapter = ContentProviderAdapter()
let section = Section()
...
init() {
//Use a string or a model, the string uses the default header view, the
//model requires you to provide a section header view
section.set(header: "")
contentAdapter.add(section: section)
//use automatically update if you'd like the table view
//to be updated every time, something is being inserted, deleted or triggered a reload.
//Default is false, so you can do multiple updates at a time
//contentAdapter.isAutoCommitEnabled = true
}
func addContent() {
section.add(row: /*Your data model*/)
// .. insert, remove models, cells ..
//find a specific instance of a model in the section
let content: <Model Type> = section.content {
//return true or false
}
//if you didn't enable the autocommit, you'll have to trigger the update manually
contentAdapter.commit()
}
func uödate
}
6) b) 或者使用 DynamicContentProviderAdapter 以自动控制内容
// in the ViewModel
struct ViewModel {
let contentAdapter = DynamicContentProviderAdapter</*Your data model*/>()
...
init() {
contentAdapter.sort = { $0 < $1 }
contentAdapter.sectionContentUpdate = { section , context in
//Update sectin content whenever a new row has been added
//use string to show the default section header view or a model, to use a custom view
section.set(header: "\(section.rows.count) Items")
//action to be used after a section update has performed (.none or .reload)
return .reload
}
//use section sorter, to sort the sections by your given algorythm
contentAdapter.sortSections = { firstSection, secondSection
guard let first = firstSection.rows.first(where: {firstSection is TimeModel}) as? TimeModel,
let second = secondSection.rows.first(where: {firstSection is TimeModel}) as? TimeModel else {
return firstSection.rows.contains(where: { firstSection is TimeModel })
}
return first.date > second.date
}
//use automatically update if you'd like the table view
//to be updated every time, something is being inserted, deleted or triggered a reload.
//Default is false, so you can do multiple updates at a time
//contentAdapter.isAutoCommitEnabled = true
contentAdapter.sectionInitializer = { section in
//Initialize sectin content the first time, a new Section has been created
//use string to show the default section header view or a model, to use a custom view
section.set(header: "\(section.rows.count) Items")
}
contentAdapter.contentSectionizer = { content, sections in
//Sectionize the content
//return .new or .use(index of the section) to create a new section or use the given section
let context = [Section.Keys.predicate: NSPredicate(format: "...")] //you can specify a predicate here, so you can easily categorize the content to the correct session
guard let last = sections?.last else {
return .new(context)
}
//Here i'm filtering the row
//if the model to be added into a section meets the given predicate of a section
(see *let context = [Section.Keys.predicate: NSPredicate(format: "...")]*)
if let index = sections.firstIndex(where: { section in
return section.meetsPredicate(content: content) ?? false
}) {
return .use(index)
}
return .new(context)
}
}
func addContent() {
contentAdapter.add(/*Your data model*/)
//if you didn't enable the autocommit, you'll have to trigger the update manually
contentAdapter.commit()
}
}
什么是 ContentProviderAdapter 和 DynamicContentProviderAdapter 之间的区别?
ContentProviderAdapter 是一个类,其中您可以控制部分和的部分中的行。这主要用于知道内容结构应如何看起来。因此,您可以向部分添加多个部分和行。
DynamicContentProviderAdapter 是一个仅提供内容并基于提供的逻辑将内容排序到某个区域的类。然而,由于 DynamicContentProviderAdapter 继承自 ContentProviderAdapter,您也可以提供自定义区域。