以前,我有一个非常简单的代码,可以对UICollectionView
执行删除操作。
// Remove from single source of truth.
viewController?.deleteTabInfo(indexPath)
//
// Perform UI updating.
//
self.collectionView.deleteItems(at: [indexPath])
效果很好
https://github.com/yccheok/ios-tutorial/tree/7a6dafbcc8c61dd525bd82ae10c6a3bd67538b7f
最近,我们计划迁移到DiffableDataSource
我们的模型非常简单
struct TabInfo {
let id: Int64
let type: TabInfoType
var name: String?
var colorIndex: Int
}
extension TabInfo: Hashable {
}
struct TabInfoSection {
var tabInfos: [TabInfo]
var footer: String
}
extension TabInfoSection: Hashable {
}
func makeDataSource() -> DataSource {
let dataSource = DataSource(
collectionView: collectionView,
cellProvider: { (collectionView, indexPath, tabInfo) -> UICollectionViewCell? in
guard let tabInfoSettingsItemCell = collectionView.dequeueReusableCell(
withReuseIdentifier: TabInfoSettingsController.tabInfoSettingsItemCellClassName,
for: indexPath) as? TabInfoSettingsItemCell else {
return nil
}
// This is used to handle delete button click event.
tabInfoSettingsItemCell.delegate = self
tabInfoSettingsItemCell.reorderDelegate = self
tabInfoSettingsItemCell.textField.text = tabInfo.getPageTitle()
return tabInfoSettingsItemCell
}
)
dataSource.supplementaryViewProvider = { collectionView, kind, indexPath in
guard kind == UICollectionView.elementKindSectionFooter else {
return nil
}
let section = dataSource.snapshot().sectionIdentifiers[indexPath.section]
guard let tabInfoSettingsFooterCell = collectionView.dequeueReusableSupplementaryView(
ofKind: kind,
withReuseIdentifier: TabInfoSettingsController.tabInfoSettingsFooterCellClassName,
for: indexPath) as? TabInfoSettingsFooterCell else {
return nil
}
tabInfoSettingsFooterCell.label.text = section.footer
return tabInfoSettingsFooterCell
}
return dataSource
}
var filteredSection: TabInfoSection {
guard let viewController = self.viewController else {
return TabInfoSection(tabInfos: [], footer: "")
}
return TabInfoSection(
tabInfos: viewController.tabInfos.filter({ $0.type != TabInfoType.Settings }),
footer: "This is footer"
)
}
func applySnapshot(_ animatingDifferences: Bool) {
var snapshot = Snapshot()
let section = filteredSection;
snapshot.appendSections([section])
snapshot.appendItems(section.tabInfos, toSection: section)
dataSource?.apply(snapshot, animatingDifferences: animatingDifferences)
}
// Remove from single source of truth.
viewController?.deleteTabInfo(indexPath)
//
// Perform UI updating.
//
applySnapshot(true)
但是,结果并不乐观。它显示了闪烁效果,而不是删除动画。
https://github.com/yccheok/ios-tutorial/tree/c26ce159472fe2d25d181f9835ef11f1081b0bbc
您知道我们错过了哪些步骤,导致删除动画无法正常工作吗?
答案 0 :(得分:0)
当前,我们不是使用枚举,而是使用struct来表示Section。
原因是,我们有一个动态的内容页脚。使用struct可以使我们为页脚携带动态内容信息。
我们最初的Section类如下
import Foundation
struct TabInfoSection {
var tabInfos: [TabInfo]
var footer: String
}
extension TabInfoSection: Hashable {
}
但是,这是一个错误。同样,我们将内容项TabInfo
作为Section的成员。
当对内容项执行任何可变操作时,这将导致Diff框架丢弃整个当前的Section,并将其替换为新的Section。 (因为Diff框架检测到Section中有更改)。
这会导致闪烁效果。
正确的实现应该是
import Foundation
struct TabInfoSection {
var footer: String
}
extension TabInfoSection: Hashable {
}
P / s但是,当我们要显式更新页脚时,这会引起其他问题。我用另一个问题来描述它-How to update footer in Section via DiffableDataSource without causing flickering effect?