对于所有解决方案,请注意无需显式调用:它会自动发生reloadData
。viewDidLoad
解决方案 1
灵感来自Samantha 的想法:invalidateLayout
异步 in viewDidLoad
.
override func viewDidLoad() {
super.viewDidLoad()
//[...]
for _ in 0 ..< 1000 {
array.append(randomKeyByBitLength(Int(arc4random_uniform(8)))!)
}
DispatchQueue.main.async {
self.collectionView.collectionViewLayout.invalidateLayout()
}
}
解决方案 2
(不完善,见 DHennessy13 改进)
基于彼得拉皮苏的回答。invalidateLayout
在viewWillLayoutSubviews
.
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
collectionView.collectionViewLayout.invalidateLayout()
}
正如 DHennessy13 所指出的,这个当前的解决方案viewWillLayoutSubviews
并不完美,因为它会在旋转屏幕时使布局无效。
您可以关注DHennessy13关于此解决方案的改进。
解决方案 3
基于Tyler Sheaffer 的回答,Shawn Aukstak 移植到 Swift和 Samantha 的想法。将您的 CollectionView 子类化以invalidateLayout
在layoutSubviews
.
class AutoLayoutCollectionView: UICollectionView {
private var shouldInvalidateLayout = false
override func layoutSubviews() {
super.layoutSubviews()
if shouldInvalidateLayout {
collectionViewLayout.invalidateLayout()
shouldInvalidateLayout = false
}
}
override func reloadData() {
shouldInvalidateLayout = true
super.reloadData()
}
}
这个解决方案很优雅,因为它不需要更改您的 ViewController 代码。我已经在这个示例项目https://github.com/Coeur/StackOverflow51375566/tree/AutoLayoutCollectionView的分支 AutoLayoutCollectionView 上实现了它。
解决方案 4
重写 UICollectionViewCell 默认约束。见拉里的回答。
解决方案 5
实施collectionView(_:layout:sizeForItemAt:)
并返回cell.contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
。见马特回答。