如何通过 DiffableDataSource 更新 Section 中的页脚而不引起闪烁效果?
How to update footer in Section via DiffableDataSource without causing flickering effect?
一个部分可以包含 1 个页眉、许多内容项和 1 个页脚。
对于DiffableDataSource
,网上的大部分例子,都是用enum
来表示Section。例如
func applySnapshot(_ animatingDifferences: Bool) {
var snapshot = Snapshot()
snapshot.appendSections([.MainAsEnum])
snapshot.appendItems(filteredTabInfos, toSection: .MainAsEnum)
dataSource?.apply(snapshot, animatingDifferences: animatingDifferences)
}
但是,当Section有动态内容页脚时,我们可能需要用struct来表示Section。例如
import Foundation
struct TabInfoSection {
// Do not include content items [TabInfo] as member of Section. If not, any mutable
// operation performed on content items, will misguide Diff framework to throw
// away entire current Section, and replace it with new Section. This causes
// flickering effect.
var footer: String
}
extension TabInfoSection: Hashable {
}
但是,我们怎么可能只更新页脚呢?
当前方法由
提供
DiffableDataSource: Snapshot Doesn't reload Headers & footers 不完全准确
如果我尝试更新页脚
class TabInfoSettingsController: UIViewController {
…
func applySnapshot(_ animatingDifferences: Bool) {
var snapshot = Snapshot()
let section = tabInfoSection;
snapshot.appendSections([section])
snapshot.appendItems(filteredTabInfos, toSection: section)
dataSource?.apply(snapshot, animatingDifferences: animatingDifferences)
}
var footerValue = 100
extension TabInfoSettingsController: TabInfoSettingsItemCellDelegate {
func crossButtonClick(_ sender: UIButton) {
let hitPoint = (sender as AnyObject).convert(CGPoint.zero, to: collectionView)
if let indexPath = collectionView.indexPathForItem(at: hitPoint) {
// use indexPath to get needed data
footerValue = footerValue + 1
tabInfoSection.footer = String(footerValue)
//
// Perform UI updating.
//
applySnapshot(true)
}
}
}
我会得到以下闪烁的结果。
闪烁的原因是,差异框架正在抛出整个旧部分,并用新部分替换它,因为它发现 TabInfoSection
对象发生了变化。
有没有什么好方法,可以通过DiffableDataSource
更新Section中的页脚而不造成闪烁效果?
p/s 整个项目的源代码可以在 https://github.com/yccheok/ios-tutorial/tree/broken-demo-for-footer-updating 文件夹下的 TabDemo 中找到。
如果您只想更新 collectionview 页脚文本,则将其设为 TabInfoSettingsFooterCell
的变量。
var tableSection: TabInfoSettingsFooterCell?
数据源
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
}
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
//set tableSection value
self.tableSection = tabInfoSettingsFooterCell
return tabInfoSettingsFooterCell
}
return dataSource
}
TabInfoSettingsItemCellDelegate
func crossButtonClick(_ sender: UIButton) {
let hitPoint = (sender as AnyObject).convert(CGPoint.zero, to: collectionView)
if let indexPath = collectionView.indexPathForItem(at: hitPoint) {
footerValue = footerValue + 1
tabInfoSection.footer = String(footerValue)
//Update section value
self.tableSection?.label.text = String(footerValue)
}
}
有一个快速修复方法,但您会丢失 tableview 的动画。在 TabInfoSettingsController.swift 中你可以在这个函数中强制动画为 false:
func applySnapshot(_ animatingDifferences: Bool) {
var snapshot = Snapshot()
let section = tabInfoSection;
snapshot.appendSections([section])
snapshot.appendItems(filteredTabInfos, toSection: section)
dataSource?.apply(snapshot, animatingDifferences: false)
}
您不会看到闪烁效果,但会失去标准动画效果。
您是否考虑过只为页脚制作一个部分?这样就没有重新加载,当它闪烁时,因为它在技术上不属于有问题的部分?
一个部分可以包含 1 个页眉、许多内容项和 1 个页脚。
对于DiffableDataSource
,网上的大部分例子,都是用enum
来表示Section。例如
func applySnapshot(_ animatingDifferences: Bool) {
var snapshot = Snapshot()
snapshot.appendSections([.MainAsEnum])
snapshot.appendItems(filteredTabInfos, toSection: .MainAsEnum)
dataSource?.apply(snapshot, animatingDifferences: animatingDifferences)
}
但是,当Section有动态内容页脚时,我们可能需要用struct来表示Section。例如
import Foundation
struct TabInfoSection {
// Do not include content items [TabInfo] as member of Section. If not, any mutable
// operation performed on content items, will misguide Diff framework to throw
// away entire current Section, and replace it with new Section. This causes
// flickering effect.
var footer: String
}
extension TabInfoSection: Hashable {
}
但是,我们怎么可能只更新页脚呢?
当前方法由
提供DiffableDataSource: Snapshot Doesn't reload Headers & footers 不完全准确
如果我尝试更新页脚
class TabInfoSettingsController: UIViewController {
…
func applySnapshot(_ animatingDifferences: Bool) {
var snapshot = Snapshot()
let section = tabInfoSection;
snapshot.appendSections([section])
snapshot.appendItems(filteredTabInfos, toSection: section)
dataSource?.apply(snapshot, animatingDifferences: animatingDifferences)
}
var footerValue = 100
extension TabInfoSettingsController: TabInfoSettingsItemCellDelegate {
func crossButtonClick(_ sender: UIButton) {
let hitPoint = (sender as AnyObject).convert(CGPoint.zero, to: collectionView)
if let indexPath = collectionView.indexPathForItem(at: hitPoint) {
// use indexPath to get needed data
footerValue = footerValue + 1
tabInfoSection.footer = String(footerValue)
//
// Perform UI updating.
//
applySnapshot(true)
}
}
}
我会得到以下闪烁的结果。
闪烁的原因是,差异框架正在抛出整个旧部分,并用新部分替换它,因为它发现 TabInfoSection
对象发生了变化。
有没有什么好方法,可以通过DiffableDataSource
更新Section中的页脚而不造成闪烁效果?
p/s 整个项目的源代码可以在 https://github.com/yccheok/ios-tutorial/tree/broken-demo-for-footer-updating 文件夹下的 TabDemo 中找到。
如果您只想更新 collectionview 页脚文本,则将其设为 TabInfoSettingsFooterCell
的变量。
var tableSection: TabInfoSettingsFooterCell?
数据源
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
}
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
//set tableSection value
self.tableSection = tabInfoSettingsFooterCell
return tabInfoSettingsFooterCell
}
return dataSource
}
TabInfoSettingsItemCellDelegate
func crossButtonClick(_ sender: UIButton) {
let hitPoint = (sender as AnyObject).convert(CGPoint.zero, to: collectionView)
if let indexPath = collectionView.indexPathForItem(at: hitPoint) {
footerValue = footerValue + 1
tabInfoSection.footer = String(footerValue)
//Update section value
self.tableSection?.label.text = String(footerValue)
}
}
有一个快速修复方法,但您会丢失 tableview 的动画。在 TabInfoSettingsController.swift 中你可以在这个函数中强制动画为 false:
func applySnapshot(_ animatingDifferences: Bool) {
var snapshot = Snapshot()
let section = tabInfoSection;
snapshot.appendSections([section])
snapshot.appendItems(filteredTabInfos, toSection: section)
dataSource?.apply(snapshot, animatingDifferences: false)
}
您不会看到闪烁效果,但会失去标准动画效果。
您是否考虑过只为页脚制作一个部分?这样就没有重新加载,当它闪烁时,因为它在技术上不属于有问题的部分?