I have 2 sections.
The top section contains unchecked items.
The bottom section contains checked items.
I was able to achieve nice move animation between the 2 sections, when I check/ uncheck the item.
The implementation is pretty straightforward by using Diffable Data Source.
enum Section: Hashable {
case unchecked
case checked
}
func applySnapshot(_ animatingDifferences: Bool) {
var snapshot = Snapshot()
snapshot.appendSections([.unchecked])
if !checkedChecklists.isEmpty {
snapshot.appendSections([.checked])
}
snapshot.appendItems(uncheckedChecklists, toSection: .unchecked)
if !checkedChecklists.isEmpty {
snapshot.appendItems(checkedChecklists, toSection: .checked)
}
dataSource.apply(snapshot, animatingDifferences: animatingDifferences)
}
func checkedButtonClicked(_ checklistCell: ChecklistCell, _ checked: Bool) {
guard let indexPath = collectionView.indexPath(for: checklistCell) else { return }
let section = indexPath.section
let item = indexPath.item
if (section == 0) {
// Unchecked
uncheckedChecklists[item].checked = checked
} else if (section == 1) {
// Checked
checkedChecklists[item].checked = checked
} else {
precondition(false)
}
applySnapshot(true)
}
However, for the header at bottom section, instead of displaying "Header with checked item", I would like to display count of checked item. I modify the code as below.
enum Section: Hashable {
case unchecked
case checked(Int)
}
func applySnapshot(_ animatingDifferences: Bool) {
var snapshot = Snapshot()
snapshot.appendSections([.unchecked])
if !checkedChecklists.isEmpty {
snapshot.appendSections([.checked(checkedChecklists.count)])
}
snapshot.appendItems(uncheckedChecklists, toSection: .unchecked)
if !checkedChecklists.isEmpty {
snapshot.appendItems(checkedChecklists, toSection: .checked(checkedChecklists.count))
}
dataSource.apply(snapshot, animatingDifferences: animatingDifferences)
}
An additional code was added to display count number in header.
class ChecklistHeader: UICollectionReusableView {
...
func update(_ section: NewChecklistViewController.Section) {
switch section {
case .unchecked:
label.text = "Header with unchecked item"
case .checked(let count):
label.text = "Header with checked item \(count)"
}
}
private func makeDataSource() -> DataSource {
let dataSource = DataSource(
...
)
dataSource.supplementaryViewProvider = { collectionView, kind, indexPath in
if kind == UICollectionView.elementKindSectionHeader {
guard let checklistHeader = collectionView.dequeueReusableSupplementaryView(
ofKind: kind,
withReuseIdentifier: "header",
for: indexPath) as? ChecklistHeader else {
return nil
}
let sectionIdentifier = self.dataSource.snapshot().sectionIdentifiers[indexPath.section]
if let section = sectionIdentifier as? Section {
checklistHeader.update(section)
}
checklistHeader.delegate = self
return checklistHeader
} else if kind == UICollectionView.elementKindSectionFooter {
...
}
return nil
}
return dataSource
}
Here's the outcome
If you observe carefully
- There is no more move animation between sections.
- This is because, Diffable Data Source, will remove old bottom section with identifier
.check(1)
, and replace with new bottom section with new identifier.check(2)
.
I was wondering, how can I retain the move animation between sections, yet able to update the content of header?