如何在不放弃动画的情况下更新集合视图补充视图?

问题描述 投票:0回答:1

以下 UIKit 应用程序使用具有组合布局(列表布局)和可比较数据源的集合视图。

如果运行它,然后点击视图控制器的右栏按钮项,

footerText
属性将会更改。

如何更新集合视图的页脚以显示更新后的

footerText
,而不干扰集合视图的动画,并且可能还采用 Apple 推荐的高性能方式?

“集合视图的动画”是指集合视图或其任何子视图的任何动画。

因此,例如,我不想通过重新加载集合视图的数据来重新配置补充视图的内容。

您可以将此问题视为一个问题,例如如何在不放弃动画的情况下保持组合布局徽章最新。

class ViewController: UIViewController {
    var collectionView: UICollectionView!
    
    var footerText = "Initial footer text"
    
    var dataSource: UICollectionViewDiffableDataSource<Section, String>!
    
    var snapshot: NSDiffableDataSourceSnapshot<Section, String> {
        var snapshot = NSDiffableDataSourceSnapshot<Section, String>()
        snapshot.appendSections(Section.allCases)
        snapshot.appendItems(["A", "a"], toSection: .first)
        return snapshot
    }
    
    enum Section: CaseIterable {
        case first
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        configureHierarchy()
        configureDataSource()
    }
    
    func configureHierarchy() {
        navigationItem.rightBarButtonItem = .init(title: "Change footer text", style: .plain, target: self, action: #selector(changeFooterText))
        
        collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: createLayout())
        view.addSubview(collectionView)
        collectionView.autoresizingMask = [.flexibleHeight, .flexibleWidth]
    }
    
    @objc func changeFooterText() {
        footerText = "Secondary footer text"
    }
    
    func configureDataSource() {
        let cellRegistration = UICollectionView.CellRegistration<UICollectionViewListCell, String> { cell, indexPath, itemIdentifier in
            var contentConfiguration = UIListContentConfiguration.cell()
            contentConfiguration.text = itemIdentifier
            cell.contentConfiguration = contentConfiguration
        }
        
        dataSource = .init(collectionView: collectionView) { collectionView, indexPath, itemIdentifier in
            collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: itemIdentifier)
        }
            
        configureSupplementaryViewProvider()
        
        dataSource.apply(self.snapshot)
    }
    
    func configureSupplementaryViewProvider() {
        let headerRegistration = UICollectionView.SupplementaryRegistration<UICollectionViewListCell>(elementKind: UICollectionView.elementKindSectionHeader) { headerView, elementKind, indexPath in
            
            var contentConfiguration = UIListContentConfiguration.cell()
            contentConfiguration.text = "Header \(indexPath.section)"
            headerView.contentConfiguration = contentConfiguration
        }
        let footerRegistration = UICollectionView.SupplementaryRegistration<UICollectionViewListCell>(elementKind: UICollectionView.elementKindSectionFooter) { [weak self] headerView, elementKind, indexPath in
            
            guard let self else { return }
            
            var contentConfiguration = UIListContentConfiguration.cell()
            contentConfiguration.text = self.footerText
            headerView.contentConfiguration = contentConfiguration
        }
        
        dataSource.supplementaryViewProvider = { collectionView, kind, indexPath in
            if kind == UICollectionView.elementKindSectionHeader {
                collectionView.dequeueConfiguredReusableSupplementary(using: headerRegistration, for: indexPath)
            } else if kind == UICollectionView.elementKindSectionFooter {
                collectionView.dequeueConfiguredReusableSupplementary(using: footerRegistration, for: indexPath)
            } else {
                nil
            }
        }
    }
    
    func createLayout() -> UICollectionViewLayout {
        UICollectionViewCompositionalLayout { section, layoutEnvironment in
            var config = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
            config.headerMode = .supplementary
            config.footerMode = .supplementary
            return NSCollectionLayoutSection.list(using: config, layoutEnvironment: layoutEnvironment)
        }
    }
}

我在

footerText
的 didSet 中尝试做的事情:

  1. 重新配置补充视图提供程序:
var footerText = "Initial footer text" {
    didSet {
        configureSupplementaryViewProvider()
    }
}
  1. 还重新应用快照:
var footerText = "Initial footer text" {
    didSet {
        configureSupplementaryViewProvider()
        dataSource.apply(self.snapshot)
    }
}
  1. 还要重新配置项目:
var footerText = "Initial footer text" {
    didSet {
        configureSupplementaryViewProvider()
        dataSource.apply(self.snapshot, animatingDifferences: true)

        var snapshot = dataSource.snapshot()
        snapshot.reconfigureItems(snapshot.itemIdentifiers)
        dataSource.apply(snapshot, animatingDifferences: false)
    }
}
uicollectionview uikit diffabledatasource uicollectionviewdiffabledatasource
1个回答
0
投票

要直接更新

supplementaryView
,您需要知道它的种类和部分。 在您的示例中,您可以将以下
didSet
代码添加到页脚文本:

var footerText = "Initial footer text" {
    didSet {
        guard let footer = collectionView.supplementaryView(forElementKind: UICollectionView.elementKindSectionFooter, at: IndexPath(row: 0, section: 0)) as? UICollectionViewListCell else { return }
        
        var contentConfiguration = UIListContentConfiguration.cell()
        contentConfiguration.text = self.footerText
        footer.contentConfiguration = contentConfiguration
    }
}

这样每次您更改 footerText 时,您的页脚都会更新。 您还可以将 contentConfiguration 更新移至单独的功能,我刚刚从您的

configureSupplementaryViewProvider

复制了它
© www.soinside.com 2019 - 2024. All rights reserved.