在 iOS 12 中,UICollectionView 何时布局单元格,在 nib 中使用 autolayout [英] In iOS 12, when does the UICollectionView layout cells, use autolayout in nib
问题描述
同样的代码
collectionLayout.estimatedItemSize = CGSize(width: 50, height: 25)
collectionLayout.itemSize = UICollectionViewFlowLayoutAutomaticSize
collectionLayout.minimumInteritemSpacing = 10
for _ in 0 ..< 1000 {
let length = Int(arc4random() % 8)
let string = randomKeyByBitLength(length)
array.append(string!)
}
collectionView.reloadData()
单元格约束:
当我在 iOS 12 上运行它时,情况有所不同.左边模拟器是iOS 11,右边是iOS 12:
when I run it on iOS 12, it's different. left simulator is iOS 11, and right is iOS 12:
但是,当我滚动它时,单元格的框架会正常.
But, when I scroll it, cells's frames will be normal.
重现问题的示例项目:https://github.com/Coeur/StackOverflow51375566p>
Sample project to reproduce the issue: https://github.com/Coeur/StackOverflow51375566
推荐答案
对于所有的解决方案,注意在viewDidLoad
中不需要显式调用reloadData
:它会自动发生.
For all solutions, note that there is no need to explicitly call reloadData
in viewDidLoad
: it will happen automatically.
灵感来自 Samantha idea:invalidateLayout
在 viewDidLoad
中异步.
Inspired by Samantha idea: invalidateLayout
asynchronously 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改进)
基于 Peter Lapisu 回答.viewWillLayoutSubviews
中的 invalidateLayout
.
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
collectionView.collectionViewLayout.invalidateLayout()
}
正如 DHennessy13 所指出的,当前使用 viewWillLayoutSubviews
的解决方案并不完美,因为它会在旋转屏幕时使布局失效.
As noted by DHennessy13, this current solution with viewWillLayoutSubviews
is imperfect as it will invalidateLayout when rotating the screen.
您可以关注 DHennessy13 改进 关于此解决方案.
You may follow DHennessy13 improvement regarding this solution.
基于Tyler Sheaffer 回答、Shawn Aukstak 移植到 Swift 和 Samantha 的想法.子类化您的 CollectionView 以在 layoutSubviews
上执行 invalidateLayout
.
Based on a combination of Tyler Sheaffer answer, Shawn Aukstak port to Swift and Samantha idea. Subclass your CollectionView to perform invalidateLayout
on 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 代码.我已经在这个示例项目的分支 AutoLayoutCollectionView 上实现了它 https://github.com/Coeur/StackOverflow51375566/tree/AutoLayoutCollectionView.
This solution is elegant as it doesn't require to change your ViewController code. I've implemented it on branch AutoLayoutCollectionView of this sample project https://github.com/Coeur/StackOverflow51375566/tree/AutoLayoutCollectionView.
重写 UICollectionViewCell 默认约束.请参阅 拉里回答.
Rewrite UICollectionViewCell default constraints. See Larry answer.
实现 collectionView(_:layout:sizeForItemAt:)
并返回 cell.contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
.请参阅 马特答案.
Implement collectionView(_:layout:sizeForItemAt:)
and return cell.contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
. See matt answer.
这篇关于在 iOS 12 中,UICollectionView 何时布局单元格,在 nib 中使用 autolayout的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!