为横向UICollectionView的分组背景视图设置正确高度
解决UICollectionView横向滚动时分组背景视图显示异常问题
问题场景
使用UICollectionView的Compositional Layout实现横向滚动的分组列表,发现分组背景视图的高度从最后一个item位置开始填充;但将CollectionView设置为纵向滚动时,背景显示完全正常。
异常显示效果

正常显示效果(纵向滚动)

问题代码
class SectionDecorationViewController: UIViewController { static let sectionBackgroundDecorationElementKind = "section-background-element-kind" var currentSnapshot: NSDiffableDataSourceSnapshot<Int, Int>! = nil var dataSource: UICollectionViewDiffableDataSource<Int, Int>! = nil var collectionView: UICollectionView! = nil var currentSelection: Bool = false override func viewDidLoad() { super.viewDidLoad() navigationItem.title = "Section Background Decoration View" configureHierarchy() configureDataSource() } } extension SectionDecorationViewController { /// - Tag: Background func createLayout() -> UICollectionViewLayout { let sectionProvider = { [weak self] (sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in guard let self = self else { return nil } let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(44)) let item = NSCollectionLayoutItem(layoutSize: itemSize) // Get the number of items in the section let itemCount = self.currentSnapshot.numberOfItems(inSection: sectionIndex) // Custom group height based on the number of items let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(CGFloat(itemCount) * 44)) let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [item]) let section = NSCollectionLayoutSection(group: group) section.orthogonalScrollingBehavior = .paging section.interGroupSpacing = 0 // Remove inter-group spacing section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0) // Remove content insets // Add the background decoration item let sectionBackgroundDecoration = NSCollectionLayoutDecorationItem.background( elementKind: SectionDecorationViewController.sectionBackgroundDecorationElementKind) section.decorationItems = [sectionBackgroundDecoration] return section } let config = UICollectionViewCompositionalLayoutConfiguration() config.scrollDirection = .horizontal config.interSectionSpacing = 0 let layout = UICollectionViewCompositionalLayout( sectionProvider: sectionProvider, configuration: config) layout.register( SectionBackgroundDecorationView.self, forDecorationViewOfKind: SectionDecorationViewController.sectionBackgroundDecorationElementKind) return layout } } extension SectionDecorationViewController { func configureHierarchy() { collectionView = UICollectionView(frame: view.bounds, collectionViewLayout: createLayout()) collectionView.autoresizingMask = [.flexibleWidth, .flexibleHeight] collectionView.backgroundColor = .systemBackground view.addSubview(collectionView) collectionView.delegate = self } func configureDataSource() { let cellRegistration = UICollectionView.CellRegistration<ListCell, Int> { (cell, indexPath, identifier) in // Populate the cell with our item description. cell.label.text = "\(indexPath.section),\(indexPath.item)" } dataSource = UICollectionViewDiffableDataSource<Int, Int>(collectionView: collectionView) { (collectionView: UICollectionView, indexPath: IndexPath, identifier: Int) -> UICollectionViewCell? in // Return the cell. return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: identifier) } // initial data let itemsPerSection = 5 let sections = Array(0..<5) currentSnapshot = NSDiffableDataSourceSnapshot<Int, Int>() var itemOffset = 0 sections.forEach { currentSnapshot.appendSections([$0]) currentSnapshot.appendItems(Array(itemOffset..<itemOffset + itemsPerSection)) itemOffset += itemsPerSection } dataSource.apply(currentSnapshot, animatingDifferences: false) } }
问题原因
当给section设置orthogonalScrollingBehavior = .paging开启横向分页滚动后,每个section的高度会和CollectionView的容器高度保持一致。但你现在是手动用itemCount * 44设置group的绝对高度,这就导致背景视图的尺寸计算和实际section高度不匹配,从而出现背景从最后一个item位置才开始填充的异常。
修复方案
把group的高度维度改成.fractionalHeight(1.0),让group自动填满整个section的高度,这样背景视图就能正确覆盖整个分组区域。同时可以移除依赖currentSnapshot获取itemCount的代码,因为不再需要手动计算高度。
修改后的createLayout方法
func createLayout() -> UICollectionViewLayout { let sectionProvider = { (sectionIndex: Int, layoutEnvironment: NSCollectionLayoutEnvironment) -> NSCollectionLayoutSection? in let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .absolute(44)) let item = NSCollectionLayoutItem(layoutSize: itemSize) // 让group高度自动填满section高度 let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1.0), heightDimension: .fractionalHeight(1.0)) let group = NSCollectionLayoutGroup.vertical(layoutSize: groupSize, subitems: [item]) let section = NSCollectionLayoutSection(group: group) section.orthogonalScrollingBehavior = .paging section.interGroupSpacing = 0 section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 0, bottom: 0, trailing: 0) let sectionBackgroundDecoration = NSCollectionLayoutDecorationItem.background( elementKind: SectionDecorationViewController.sectionBackgroundDecorationElementKind) section.decorationItems = [sectionBackgroundDecoration] return section } let config = UICollectionViewCompositionalLayoutConfiguration() config.scrollDirection = .horizontal config.interSectionSpacing = 0 let layout = UICollectionViewCompositionalLayout( sectionProvider: sectionProvider, configuration: config) layout.register( SectionBackgroundDecorationView.self, forDecorationViewOfKind: SectionDecorationViewController.sectionBackgroundDecorationElementKind) return layout }
内容的提问来源于stack exchange,提问作者harshalb
相关产品推荐
相关产品推荐

