DiffableDataSource - 无动画,但在删除操作期间闪烁
Posted
技术标签:
【中文标题】DiffableDataSource - 无动画,但在删除操作期间闪烁【英文标题】:DiffableDataSource - No animation, but flickering during delete operation 【发布时间】:2020-10-11 16:26:25 【问题描述】:以前,我有一个非常简单的代码,它对UICollectionView
执行删除操作。
// Remove from single source of truth.
viewController?.deleteTabInfo(indexPath)
//
// Perform UI updating.
//
self.collectionView.deleteItems(at: [indexPath])
效果很好
完整的源代码(带有可行删除动画的TabDemo)
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)
但是,结果并不乐观。不是删除动画,而是显示闪烁效果。
完整的源代码(删除时有闪烁效果的TabDemo)
https://github.com/yccheok/ios-tutorial/tree/c26ce159472fe2d25d181f9835ef11f1081b0bbc
您知道我们遗漏了哪些步骤,导致删除动画无法正常工作吗?
【问题讨论】:
【参考方案1】:目前,我们不使用 enum,而是使用 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?
【讨论】:
以上是关于DiffableDataSource - 无动画,但在删除操作期间闪烁的主要内容,如果未能解决你的问题,请参考以下文章
UICollectionViewController + diffableDataSource - 当您的手指仍在其上时,单元格不会突出显示
DiffableDataSource CollectionView 在部分中不返回任何项目
DiffableDataSource 抛出“致命:提供的标识符不是唯一的。”将 MPMediaItem 包装在结构中时