所以我有一个带有 Diffable DataSource List CollectionView 的屏幕,当 ManagedContext 发生更改时,它将重新加载。
我现在重新加载的问题是单元格一直在随机变化,并且大多数时候它们会用来自不同部分的项目复制自己。
什么是重新加载这个的好解决方案?
class MultiSectionExpandableListView: UIView {
weak var delegate: MultiSectionExpandableListViewDelegate?
private var objects: [HeaderItem]
private var collectionView: UICollectionView!
private var dataSource: UICollectionViewDiffableDataSource<HeaderItem, ItemType>!
private lazy var noEntriesView: NoEntriesView = {
let view = NoEntriesView.instantiateNib()
view.frame = collectionView.bounds
return view
}()
init(frame: CGRect, objects: [HeaderItem]) {
self.objects = objects
super.init(frame: frame)
setupCollectionView()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupCollectionView() {
var layoutConfig = UICollectionLayoutListConfiguration(appearance: .sidebar)
layoutConfig.headerMode = .firstItemInSection
layoutConfig.showsSeparators = false
layoutConfig.backgroundColor = .clear
let listLayout = UICollectionViewCompositionalLayout.list(using: layoutConfig)
collectionView = UICollectionView(frame: bounds, collectionViewLayout: listLayout)
collectionView.delegate = self
collectionView.backgroundColor = .clear
addSubview(collectionView)
collectionView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
collectionView.topAnchor.constraint(equalTo: topAnchor),
collectionView.leadingAnchor.constraint(equalTo: leadingAnchor),
collectionView.trailingAnchor.constraint(equalTo: trailingAnchor),
collectionView.bottomAnchor.constraint(equalTo: bottomAnchor)])
guard objects[0].items.count > 0 || objects[1].items.count > 0 || objects[2].items.count > 0 || objects[3].items.count > 0 else {
collectionView.backgroundView = noEntriesView
return
}
let headerCellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, HeaderItem> {
(cell, indexPath, headerItem) in
var content = cell.defaultContentConfiguration()
content.text = headerItem.title
cell.contentConfiguration = content
var headerDisclosureOption = UICellAccessory.OutlineDisclosureOptions(style: .header)
headerDisclosureOption.tintColor = AppStorage.tintColor.uiColor()
cell.accessories = [.outlineDisclosure(options:headerDisclosureOption)]
}
let itemCellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, ListItem> {
(cell, indexPath, listItem) in
var configuration = cell.defaultContentConfiguration()
configuration.text = listItem.title
configuration.secondaryText = listItem.description
configuration.imageProperties.maximumSize = CGSize(width: 50, height: 50)
configuration.imageProperties.reservedLayoutSize = CGSize(width: 60, height: 60)
let spinner = UIActivityIndicatorView(style: .large)
spinner.color = AppStorage.tintColor.uiColor()
spinner.startAnimating()
cell.accessories = [.customView(configuration: UICellAccessory.CustomViewConfiguration(customView: spinner, placement: .leading(displayed: .always)))]
cell.contentConfiguration = configuration
DownloadImageService.shared.loadImage(stringUrl: listItem.imageURL) { (data, error) in
guard error == nil, let data = data else { return }
configuration.image = UIImage(data: data)
cell.accessories = []
cell.contentConfiguration = configuration
}
}
dataSource = UICollectionViewDiffableDataSource<HeaderItem, ItemType>(collectionView: collectionView) {
(collectionView, indexPath, itemType) -> UICollectionViewCell? in
switch itemType {
case .header(let headerItem):
let cell = collectionView.dequeueConfiguredReusableCell(using: headerCellRegistration, for: indexPath, item: headerItem)
return cell
case .cell(let listItem):
let cell = collectionView.dequeueConfiguredReusableCell(using: itemCellRegistration, for: indexPath, item: listItem)
cell.backgroundConfiguration?.backgroundColor = .clear
return cell
}
}
var currentSnapshot = NSDiffableDataSourceSnapshot<HeaderItem, ItemType>()
currentSnapshot.appendSections(objects)
dataSource.apply(currentSnapshot)
for headerItem in objects {
var sectionSnapshot = NSDiffableDataSourceSectionSnapshot<ItemType>()
let headerListItem = ItemType.header(headerItem)
sectionSnapshot.append([headerListItem])
let listItemArray = headerItem.items.map { ItemType.cell($0) }
sectionSnapshot.append(listItemArray, to: headerListItem)
sectionSnapshot.expand([headerListItem])
dataSource.apply(sectionSnapshot, to: headerItem, animatingDifferences: false)
}
}
func reloadCollectionView(with newObjects: [HeaderItem]) {
objects = newObjects
guard objects[0].items.count > 0 || objects[1].items.count > 0 || objects[2].items.count > 0 || objects[3].items.count > 0 else {
collectionView.backgroundView = noEntriesView
return
}
var currentSnapshot = dataSource.snapshot()
currentSnapshot = NSDiffableDataSourceSnapshot<HeaderItem, ItemType>()
currentSnapshot.appendSections(objects)
dataSource.apply(currentSnapshot)
for headerItem in objects {
var sectionSnapshot = NSDiffableDataSourceSectionSnapshot<ItemType>()
let headerListItem = ItemType.header(headerItem)
sectionSnapshot.append([headerListItem])
let listItemArray = headerItem.items.map { ItemType.cell($0) }
sectionSnapshot.append(listItemArray, to: headerListItem)
sectionSnapshot.expand([headerListItem])
dataSource.apply(sectionSnapshot, to: headerItem, animatingDifferences: false)
}
}
}
还有我的对象:
struct ListItem: Hashable {
let title: String
let description: String
let imageURL: String
}
struct HeaderItem: Hashable {
let title: String
let items: [ListItem]
}
enum ItemType: Hashable {
case header(HeaderItem)
case cell(ListItem)
}