ConfigableCollectionView
中文文档
以类似于iOS 13中新引入的DataSource的方式创建CollectionView
示例基于Apple的ImplementingModernCollectionViews。
优势
覆盖率超过90%
支持更多iOS版本
UICollectionViewDiffableDataSource:iOS 13必备
可配置UICollectionView: 需要 iOS 9,但技术上支持自 iOS 6 以来的所有 iOS 版本
更安全
UICollectionViewDiffableDataSource: 一旦添加重复对象就会崩溃,即使在发布版,有时在某些 iOS 版本上也会发生
ConfigableCollectionView : 仅在调试时添加重复对象时断言
更简单
NSDiffableDataSourceSectionSnapshot 和 NSDiffableDataSourceSnapshot 没有区别
单元格点击基于 hittest,而不是 cell.bounds(这就是 UICollectionView 的工作方式),因此您可以通过覆盖视图的 hittest 来确保您的点击操作正常工作。
支持多种项目类型和分区
UICollectionViewDiffableDataSource : 仅支持一种分区类型和一种项目类型
ConfigableCollectionView: 支持多个项目类型和分区
用法
初始化
用于特定项目类型
let collectionView = CollectionView<Section, Item>(layout: generateLayout())
支持多种各项类型和多种区域类型
let collectionView = CollectionView<Any, Any>(layout: generateLayout())
注册
用于特定项类型
collectionView.register(
view: { // create view for reuse
UICollectionViewListCell()
},
.config { // config the UICollectionViewListCell with Item
let cell = $0.view
let item = $0.data
var contentConfiguration = cell.defaultContentConfiguration()
contentConfiguration.text = item.title
contentConfiguration.textProperties.font = .preferredFont(forTextStyle: .headline)
cell.contentConfiguration = contentConfiguration
let disclosureOptions = UICellAccessory.OutlineDisclosureOptions(style: .header)
cell.accessories = [.outlineDisclosure(options:disclosureOptions)]
cell.backgroundConfiguration = UIBackgroundConfiguration.clear()
},
.when { // Optional, deciding when to use this type of view if need
!$0.data.subitems.isEmpty
}
)
collectionView.register(
view { // create normal view for reuse
ContentView()
},
.config(map: \.title) { // config the ContentView with Item.title, configurationState: UICellConfigurationState(introduced in iOS 14, no useful when you using UICollectionViewCell as View)
$0.view.data = $0.data
if $0.configurationState.isHighlighted {
$0.view.backgroundColor = .red
}
...
},
.flowLayoutSize { _ in // Optional, deciding the size in flow layout
CGSize(width: 100, height: 100)
},
.tap { _ in // Optional, deciding what to do after tap the view
Router.push( ... )
}
)
...
使用多种项类型
collectionView.register(
dataType: Int.self,
view {
ContentView()
},
.config {
$0.view.data = $0.data
}
)
collectionView.register(
dataType: String.self,
view {
UILabel()
},
.config {
$0.view.text = $0.data
}
)
视图封装是支持在视图创建时配置对象弱引用的视图构建器,例如
collectionView.register(
dataType: Int.self,
view { [weak self] in
if let color = self?.color {
ContentView(color: color)
}
},
.config {
$0.view.data = $0.data
}
)
注意:如果您使用UICollectionView的子类,则不会使用视图封装创建视图,而是使用UICollectionView.dequeue。
设置数据,与UICollectionViewDiffableDataSource非常相似
类似
collectionView.dataManager.appendSections([Section.main])
collectionView.dataManager.appendItems(mountains)
or just
collectionView.dataManager.applyItems(mountains, updatedSection: Section.main)
或
在appendChildItems中支持recursivePath
collectionView.dataManager.appendChildItems(menuItems, to: nil, recursivePath: \.subitems)
is equal to:
func addItems(_ menuItems: [OutlineItem], to parent: OutlineItem?) {
collectionView.dataManager.appendChildItems(menuItems, to: parent)
for menuItem in menuItems where !menuItem.subitems.isEmpty {
addItems(menuItem.subitems, to: menuItem)
}
}
addItems(menuItems, to: nil)
或
在同一个区域使用多种项类型
let numbers: [Int]
let stings: [String]
collectionView.dataManager.appendItems(numbers)
collectionView.dataManager.appendItems(stings)
collectionView.register(
dataType: Int.self,
view {
NumberView()
}
)
collectionView.register(
dataType: String.self,
view {
UILabel()
}
)
动画和更新完成回调,在所有数据处理函数之后使用.on(animatingDifferences: completion),例如:
collectionView.dataManager.appendItems(stings)
.on(animatingDifferences: false, completion: { print("appended") })
有关更多使用信息,请查阅《ImplementingModernCollectionViews》的差别。
注意
为了支持旧版本iOS,在iOS 13以上使用NSDiffableDataSourceSnapshot,而在iOS 13以下直接将数据放入CustomUICollectionViewDataSource,以减少重新创建NSDiffableDataSourceSnapshot实例的数量,因此CollectionView的刷新细胞是异步的。为了避免这种情况,您可以调用reloadImmediately()。
您可以使用自己的UICollectionViewDelegate(某些委托函数不会调用),但不能重置UICollectionViewDataSource。
已知问题
由于性能问题,无法实现添加子项的过滤,所以仍然直接添加到NSDiffableDataSourceSectionSnapshot中,如果在发布时添加重复对象,则会崩溃。
因为它将重新创建NSDiffableDataSourceSnapshot实例,如果在基于iOS 14的NSDiffableDataSourceSnapshot之上的数据处理函数中使用,则不会保存展开状态,如果更改数据,则会折叠所有项。
安装
pod 'ConfigableCollectionView'
待办事项列表
- 高效的添加子项的过滤器。
- 区分iOS 13以上数据处理函数的成就,以解决重新创建NSDiffableDataSourceSnapshot实例的问题。
- 移除Proxy.m以支持Swift包管理器或等待它支持.m文件。
- TVOS支持。
- 文档补充。