使用transition方法切换控制器时NSCollectionView Item尺寸异常,求解决
我之前也碰到过一模一样的问题!用transition(from: to: options: completionHandler:)切换控制器时,NSCollectionView的Item尺寸乱掉,调整窗口大小又恢复正常——本质是切换过程中CollectionView没收到正确的布局更新触发信号,导致它沿用了错误的尺寸缓存或者没完成初始化布局。给你几个亲测有效的解决办法:
在切换完成后手动触发布局刷新
这是最直接的解决方案,在transition的完成回调里,强制让目标控制器的CollectionView重新计算布局并立即执行:transition(from: currentViewController, to: targetCollectionVC, options: .crossDissolve, completionHandler: { _ in // 先让布局失效,重新计算所有Item尺寸 targetCollectionVC.collectionView?.collectionViewLayout.invalidateLayout() // 立即执行布局,不用等下一个RunLoop周期 targetCollectionVC.collectionView?.layoutSubtreeIfNeeded() })这个方法能快速解决大部分场景下的尺寸异常问题,我当时就是靠这个搞定的。
检查CollectionView的布局估算尺寸配置
如果用的是NSCollectionViewFlowLayout,确保estimatedItemSize没有设为不合理的值(比如CGSize.zero)。macOS 10.13及以上可以直接用自动尺寸:let flowLayout = NSCollectionViewFlowLayout() // 自动估算Item尺寸,依赖Item内部的Auto Layout约束 flowLayout.estimatedItemSize = NSCollectionViewFlowLayout.automaticSize collectionView.collectionViewLayout = flowLayout要是用的是较早系统版本,就设置一个和实际Item尺寸接近的估算值,这样布局系统不会在切换时用错误的默认值来渲染Item。
在目标控制器的视图显示后触发布局
有时候控制器切换时,目标视图还没完全加载完成,导致布局初始化不完整。可以在目标控制器的viewDidAppear(_:)方法里补一次布局刷新:override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) collectionView?.collectionViewLayout.invalidateLayout() }等视图完全显示后再强制刷新,能保证布局基于当前视图的正确尺寸计算。
自定义布局的特殊处理
如果你用的是自定义NSCollectionViewLayout,要确保布局能响应视图边界变化。重写shouldInvalidateLayout(forBoundsChange:)方法,返回true:override func shouldInvalidateLayout(forBoundsChange newBounds: NSRect) -> Bool { return true }这样当控制器切换导致视图边界变化时,布局会自动重新计算Item尺寸。
你可以先从第一个方法试起,一般都能解决问题,如果不行再依次排查后面的配置点。
内容的提问来源于stack exchange,提问作者Jia Jia

