ios - DiffableDataSource:快照不重新加载页眉和页脚
问题描述
我正在使用UICollectionViewDiffableDataSource
forUICollectionView
在多个部分中显示内容。
我正在使用 WWDC'19 中引入的 Collection View Compositional Layout and Diffable Datasources链接来呈现多节布局UICollectionView
我有一个简单的设置,每个部分的标题显示该部分中的项目数,页脚显示该部分所有项目的摘要。
第 1 节标题--> 2020 年 1 月 - 5 次旅行
第 1 节第 1 项-->第 1
节第 1 项第 2节--> 第 2
节第 1 项第 3节--> 第 3 节第 1 节第 4 项--> 第
4
节第 1 项5 --> 行程 5
现在如果删除行程,DiffableDataSource 会通过动画更新更改,但不会重新加载部分的标题。这看起来不一致。例如,如果行程 4 被删除,那么标题仍然显示该部分中有 5 个行程。如何让标头也使用 DiffableDataSource 重新加载?
对于临时修复,我只是
collectionView.reloadData()
在显示 Diffing 动画的延迟后调用,然后我硬重新加载数据,这也会强制重新加载标题。
private func configureTripDataSource(){
tripDataSource = UICollectionViewDiffableDataSource<MonthSection, Trip>(collectionView: tripsCollectionView, cellProvider: { (collectionView, indexPath, trip) -> UICollectionViewCell? in
// Get a cell of the desired kind.
guard let cell = collectionView.dequeueReusableCell(
withReuseIdentifier: TripInfoCell.reuseIdentifier,
for: indexPath) as? TripInfoCell else { fatalError("Cannot create new TripInfoCell") }
// Populate the cell with our item description.
cell.trip = trip
// Return the cell.
return cell
})
tripDataSource.supplementaryViewProvider = {
[weak self] (collectionView: UICollectionView, kind: String, indexPath: IndexPath) -> UICollectionReusableView? in
guard let self = self else {return nil}
if kind == TripsController.tripsMonthSectionHeaderElementKind{
// Get a supplementary view of the desired kind.
guard let header = collectionView.dequeueReusableSupplementaryView(
ofKind: kind,
withReuseIdentifier: TripSectionHeaderCell.reuseIdentifier,
for: indexPath) as? TripSectionHeaderCell else { fatalError("Cannot create new header") }
// setup header
let currentSnapShot = self.tripDataSource.snapshot()
let tripMonthSection = currentSnapShot.sectionIdentifiers[indexPath.section]
header.titleLabel.text = tripMonthSection.title
header.subtitleLabel.text = "\(tripMonthSection.trips.count) Trips"
return header
} else {
return UICollectionReusableView()
}
}
var snapshot = NSDiffableDataSourceSnapshot<MonthSection, Trip>()
let allSections = self.tripsStore.monthSections
snapshot.appendSections(allSections)
for section in allSections{
snapshot.appendItems(section.trips, toSection: section)
}
self.tripDataSource.apply(snapshot, animatingDifferences: true)
}
解决方案
要触发标题的自动重新加载,您的Section对象应该是Hashable并且应该存储所有必要的属性来为 Section 创建唯一的哈希。
这就是为什么所有Section对象和Item对象都应该是Hashable的,并且它们应该返回一个唯一的哈希值以允许DiffableDataSource仅在它们的值发生更改时管理它们的重新加载。
例如:
struct MonthSection: Hashable {
var title: String
var itemsCount: Int
}
接着:
var section = MonthSection(title: "Title", itemsCount: 5)
.....
snapshot.appendSections([section])
snapshot.appendItems(items, toSection: section)
在快照的下一次更新期间,该部分的标题或项目计数的任何更改都将触发部分标题重新加载,它将像魔术一样工作!
推荐阅读
- java - 在 Java 流中组合相似的元素
- c++ - g++10、C++20、boost 1.75.0 :: 错误:“awaitable”尚未在“boost::asio”中声明
- django - Django 只在循环中显示第一个 POST 元素
- python-3.x - 使用curve_fit拟合SIR模型的问题
- r - 如何将文本和元数据从子单元聚合到更大的单元?
- java - 如何在java 8中对出现的元素计数求和
- javascript - 为什么我保存更改时“webpack serve”命令不刷新 html 页面?
- powershell - Powershell 不允许我打开 firebase CLI
- node.js - 使用 AccessControl NPM 包实现 ABAC?
- python - 从 dict 创建饼图并更改箭头