我想创建一个collectionView
也可以折叠的动态部分。使用 iOS 14中的新功能,这似乎很容易section snapshots
。这就是我所拥有的(完全工作的示例)。
import UIKit
enum Section: Hashable {
case group(Int)
}
enum Item: Hashable {
case header(Int)
case item(String)
}
class ViewController: UIViewController {
private var dataSource: UICollectionViewDiffableDataSource<Section, Item>!
private var groups = [1, 2, 3, 4, 5]
private var groupItems: [Int: [String]] = [
1: ["A", "B", "C", "D"],
2: ["E", "F", "G", "H"],
3: ["I", "J", "K", "L"],
4: ["M", "N", "O", "P"],
5: ["Q", "R", "S", "T"],
]
private lazy var collectionView: UICollectionView = {
var config = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
config.headerMode = .firstItemInSection
let layout = UICollectionViewCompositionalLayout.list(using: config)
let collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: layout)
collectionView.backgroundColor = .systemGroupedBackground
return collectionView
}()
override func viewDidLoad() {
super.viewDidLoad()
view.addSubview(collectionView)
collectionView.frame = view.bounds
configureDataSource()
applySnapshot()
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2)) {
self.groups.remove(at: 0) // This removes the entire first section
self.applySnapshot()
}
}
private func configureDataSource() {
let itemCellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, String> {
(cell, indexPath, letter) in
var content = cell.defaultContentConfiguration()
content.text = letter
cell.contentConfiguration = content
}
let headerCellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, Int> {
(cell, indexPath, number) in
var content = cell.defaultContentConfiguration()
content.text = String(number)
cell.contentConfiguration = content
let headerDisclosureOption = UICellAccessory.OutlineDisclosureOptions(style: .header)
cell.accessories = [.outlineDisclosure(options: headerDisclosureOption)]
}
dataSource = UICollectionViewDiffableDataSource<Section, Item>(collectionView: collectionView, cellProvider: { (collectionView, indexPath, item) -> UICollectionViewCell? in
switch item {
case .header(let number):
return collectionView.dequeueConfiguredReusableCell(using: headerCellRegistration, for: indexPath, item: number)
case .item(let letter):
return collectionView.dequeueConfiguredReusableCell(using: itemCellRegistration, for: indexPath, item: letter)
}
})
}
private func applySnapshot() {
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
snapshot.appendSections(groups.map { .group($0) })
// This line causes the error messages. If I comment it out, the messages go away but changing sections (removing or adding some) doesn't work any more (the collectionview does not reflect the changes of the sections)
dataSource.apply(snapshot, animatingDifferences: false)
for group in groups {
var sectionSnapshot = NSDiffableDataSourceSectionSnapshot<Item>()
// header
let headerItem = Item.header(group)
sectionSnapshot.append([headerItem])
// items
sectionSnapshot.append((groupItems[group] ?? []).map { Item.item($0) }, to: headerItem)
sectionSnapshot.expand([headerItem])
dataSource.apply(sectionSnapshot, to: .group(group))
}
}
}
这只是一个简单的集合视图,显示几个部分,每个部分有 4 个项目。为了演示我的问题,我添加了一个在加载视图控制器 2 秒后自动调用的闭包。它删除了第一部分并更新了 collectionview 的数据源。
有两个问题:
首先,它给了我这些错误信息:
sectionSnapshotExample[15380:1252802] [DiffableDataSource] Failed to find index of item sectionSnapshotExample.Item.header(1)
sectionSnapshotExample[15380:1252802] [DiffableDataSource] Failed to find index of item sectionSnapshotExample.Item.header(4)
sectionSnapshotExample[15380:1252802] [DiffableDataSource] Failed to find index of item sectionSnapshotExample.Item.header(2)
sectionSnapshotExample[15380:1252802] [DiffableDataSource] Failed to find index of item sectionSnapshotExample.Item.header(3)
sectionSnapshotExample[15380:1252802] [DiffableDataSource] Failed to find index of item sectionSnapshotExample.Item.header(5)
其次,更新在视觉上并不好,因为它重新加载了整个集合视图(所有单元格都在交叉淡入淡出,即使它们没有改变)。
错误是在applySnapshot()
方法内部引起的:
private func applySnapshot() {
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
snapshot.appendSections(groups.map { .group($0) })
// This line causes the error messages
dataSource.apply(snapshot, animatingDifferences: false)
....
}
这会将这些部分应用于数据源(Apple 在他们的示例项目中也是如此)。
如果我将此行注释掉,则这些部分将不再更新(在此示例中,已删除的部分将保留在集合视图中。
有任何想法吗?我做错了吗?section snapshots
不打算与动态内容一起使用吗?如果是这样,是否有另一种简单的方法来拥有可折叠的部分?
谢谢!