UICollectionViewCompositionalLayout是否支持手动计算宽高并动态修改NSCollectionLayoutSize?
解决方案
UICollectionViewCompositionalLayout 完全支持手动指定精确尺寸,无需被迫使用预估布局,动态修改 NSCollectionLayoutSize 可以通过以下两种方案实现,完美匹配你提前计算尺寸存储在ViewModel的使用习惯:
方案1:基于Section维度动态配置尺寸
使用 UICollectionViewCompositionalLayout 的闭包构造器 init(sectionProvider:),在闭包中根据当前Section的索引,读取ViewModel中提前计算好的对应Section配置,生成对应的布局参数即可,示例代码如下:
let layout = UICollectionViewCompositionalLayout { [weak self] sectionIndex, layoutEnvironment in guard let self = self, let currentSectionVM = self.viewModel.sections[sectionIndex] else { // 异常场景返回默认占位布局 let defaultSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(44)) let item = NSCollectionLayoutItem(layoutSize: defaultSize) let group = NSCollectionLayoutGroup.horizontal(layoutSize: defaultSize, subitems: [item]) return NSCollectionLayoutSection(group: group) } // 直接读取VM中提前计算好的尺寸 let itemSize = NSCollectionLayoutSize( widthDimension: .absolute(currentSectionVM.itemFixedWidth), heightDimension: .absolute(currentSectionVM.itemFixedHeight) ) let item = NSCollectionLayoutItem(layoutSize: itemSize) // 可根据业务配置设置横向滚动逻辑 let groupSize = NSCollectionLayoutSize( widthDimension: currentSectionVM.enableHorizontalScroll ? .absolute(currentSectionVM.contentTotalWidth) : .fractionalWidth(1), heightDimension: .absolute(currentSectionVM.sectionFixedHeight) ) let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) let section = NSCollectionLayoutSection(group: group) if currentSectionVM.enableHorizontalScroll { section.orthogonalScrollingBehavior = .continuous } return section }
方案2:同一Section下不同Item动态配置尺寸
如果同一个Section内不同Item的尺寸存在差异,可以使用 NSCollectionLayoutGroup 的 init(layoutSize:itemProvider:) 构造器,在itemProvider闭包中根据当前Item的索引读取ViewModel中预存的尺寸,生成对应的Item布局:
let group = NSCollectionLayoutGroup.horizontal( layoutSize: groupSize, itemProvider: { [weak self] itemIndex, layoutEnvironment in guard let self = self, let currentItemVM = currentSectionVM.items[itemIndex] else { return NSCollectionLayoutItem(layoutSize: NSCollectionLayoutSize(widthDimension: .absolute(0), heightDimension: .absolute(0))) } // 读取提前计算好的单个Item尺寸 let itemSize = NSCollectionLayoutSize( widthDimension: .absolute(currentItemVM.preCalculatedWidth), heightDimension: .absolute(currentItemVM.preCalculatedHeight) ) return NSCollectionLayoutItem(layoutSize: itemSize) } )
注意事项
- 上述两种方案均使用绝对尺寸,不需要开启估算逻辑,布局只会在数据刷新时读取一次ViewModel中的预计算尺寸,滑动过程中不会重复计算,和你之前使用YYKit布局的性能表现一致
- 后续如果需要更新某个Item/Section的尺寸,只要修改ViewModel中对应的预计算值,调用UICollectionView的刷新接口即可,布局会自动读取最新的尺寸配置
内容的提问来源于stack exchange,提问作者viviyoung
相关产品推荐
相关产品推荐

