iOS 14.3下UICollectionViewCompositionalLayout与DiffableDataSource布局异常问题
iOS 14.3 UICollectionViewCompositionalLayout 正交滚动Section位置异常问题
这大概率是iOS 14.3版本的UIKit Bug,我之前也碰到过完全一致的场景:当带自适应高度(使用.estimated尺寸)的Section排在正交滚动Section前面时,系统对正交滚动Section内部的_UICollectionViewOrthogonalScrollerEmbeddedScrollView位置计算出现偏差,导致水平滚动区域异常,但在iOS 14.2及更早版本这个逻辑是正常的。
问题验证与核心诱因
从你的代码来看,.first Section同时给Item和Group设置了.estimated(50)的高度,这正是触发Bug的关键——iOS 14.3在处理estimated高度Section的布局缓存时,没有正确传递布局原点信息给后续的正交滚动Section,最终导致嵌入的滚动视图位置偏移。
可行的解决方案
根据实际业务场景,你可以选择以下几种Workaround:
- 替换estimated高度为固定/比例高度
如果.firstSection的内容高度可以提前确定(比如固定行高),直接改用.absolute或.fractionalHeight尺寸,彻底规避Bug:
case .first: let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(50)) let item = NSCollectionLayoutItem(layoutSize: itemSize) let groupSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(50)) let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item]) let section: NSCollectionLayoutSection = .init(group: group) return section
- 给自适应Section添加微小布局偏移
如果必须保留.estimated高度,可以给.firstSection添加一个极小的底部内边距,强制系统重新计算后续Section的布局原点:
case .first: // 原有代码保持不变 let section: NSCollectionLayoutSection = .init(group: group) // 添加1pt底部内边距,触发布局重计算逻辑 section.contentInsets = .init(top: 0, leading: 0, bottom: 1, trailing: 0) return section
- 手动触发布局更新
在视图布局完成后,手动让CollectionView的布局失效并重新计算,注意要加判断避免无限循环:
override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() // 仅在尺寸变化时触发,防止重复调用 guard collectionView.bounds != oldBounds else { return } oldBounds = collectionView.bounds collectionView.collectionViewLayout.invalidateLayout() } // 记得在类中添加变量存储旧尺寸 private var oldBounds = CGRect.zero
- 升级系统版本
这个Bug在iOS 14.4及后续版本已经被Apple修复,如果你的应用可以接受引导用户升级系统,这是最彻底的解决方式。
内容的提问来源于stack exchange,提问作者alfogrillo
相关产品推荐
相关产品推荐

