Previously, I have a pretty straightforward code, which perform delete operation for UICollectionView
.
// Remove from single source of truth.
viewController?.deleteTabInfo(indexPath)
//
// Perform UI updating.
//
self.collectionView.deleteItems(at: [indexPath])
It works pretty well
Complete source code (TabDemo with workable delete animation)
https://github.com/yccheok/ios-tutorial/tree/7a6dafbcc8c61dd525bd82ae10c6a3bd67538b7f
Recently, we plan to migrate to DiffableDataSource
Our models are pretty straightforward
Model
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 {
}
Data source
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
}
Snapshot
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)
}
Delete operation
// Remove from single source of truth.
viewController?.deleteTabInfo(indexPath)
//
// Perform UI updating.
//
applySnapshot(true)
However, the outcome is not promising. Instead of delete animation, it is showing flickering effect.
Complete source code (TabDemo with flickering effect during deletion)
https://github.com/yccheok/ios-tutorial/tree/c26ce159472fe2d25d181f9835ef11f1081b0bbc
Do you have idea what steps we have missed out, which causes delete animation doesn't work properly?