Evi*_*dra 44 ios uicollectionview ios-autolayout ios12 xcode10
像这样的代码
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()
Run Code Online (Sandbox Code Playgroud)
细胞限制:
当我在iOS 12上运行它时,它是不同的.左模拟器是iOS 11,右边是iOS 12:
但是,当我滚动它时,细胞的帧将是正常的.
Cœu*_*œur 41
对于所有的解决方案,请注意,没有必要显式调用reloadData
的viewDidLoad
:它会自动发生.
灵感来自萨曼莎的想法:invalidateLayout
异步进入viewDidLoad
.
override func viewDidLoad() {
super.viewDidLoad()
//[...]
for _ in 0 ..< 1000 {
array.append(randomKeyByBitLength(Int(arc4random_uniform(8)))!)
}
DispatchQueue.main.async {
self.collectionView.collectionViewLayout.invalidateLayout()
}
}
Run Code Online (Sandbox Code Playgroud)
(不完美,见DHennessy13对它的改进)
根据Peter Lapisu的回答.invalidateLayout
在viewWillLayoutSubviews
.
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
collectionView.collectionViewLayout.invalidateLayout()
}
Run Code Online (Sandbox Code Playgroud)
正如DHennessy13所指出的那样,当前的解决方案viewWillLayoutSubviews
并不完美,因为它会在旋转屏幕时使布局无效.
您可以关注此解决方案的DHennessy13改进.
基于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()
}
}
Run Code Online (Sandbox Code Playgroud)
此解决方案非常优雅,因为它不需要更改ViewController代码.我已经在这个示例项目的分支AutoLayoutCollectionView上实现了它https://github.com/Coeur/StackOverflow51375566/tree/AutoLayoutCollectionView.
重写UICollectionViewCell默认约束.见拉里的回答.
实施collectionView(_:layout:sizeForItemAt:)
并返回cell.contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
.见哑光答案.
Lar*_*rry 28
这是另一个解决Cœur代码示例的解决方案,也适用于我的特定情况,其他答案没有.下面的代码替换了以前的CollectionViewCell
子类实现ViewController.swift
:
class CollectionViewCell: UICollectionViewCell {
@IBOutlet weak var label: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
contentView.translatesAutoresizingMaskIntoConstraints = false
let leftConstraint = contentView.leftAnchor.constraint(equalTo: leftAnchor)
let rightConstraint = contentView.rightAnchor.constraint(equalTo: rightAnchor)
let topConstraint = contentView.topAnchor.constraint(equalTo: topAnchor)
let bottomConstraint = contentView.bottomAnchor.constraint(equalTo: bottomAnchor)
NSLayoutConstraint.activate([leftConstraint, rightConstraint, topConstraint, bottomConstraint])
}
}
Run Code Online (Sandbox Code Playgroud)
这是通过回答启发ale84从UICollectionViewFlowLayout estimatedItemSize并不虽然它正常工作与iOS 11. iOS12正常工作*
mat*_*att 23
问题是这里假设的特征 - 基于其内部约束自行调整大小的集合视图单元 - 不存在.它从未存在过.Apple声称确实如此,但事实并非如此.自收集意见出台以来,我每年都对此提出了一个错误.我的错误报告从未被关闭,因为错误是真实的.没有自我调整集合视图单元格这样的东西.
另见我的回答:https://stackoverflow.com/a/51585910/341994 \
在某些年份,尝试使用自我大小的细胞已经崩溃.在其他年份,它不会崩溃,但它会使布局错误.但它不起作用.
在只有做这样的事情的方式是实现委托方法sizeForItemAt
并提供大小自己.您可以通过致电轻松完成
cell.contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize)
Run Code Online (Sandbox Code Playgroud)
在您事先配置的模型单元格上.这就是运行时应该为你做的事情 - 但事实并非如此.
所以这是我对原始问题的解决方案.我们生成了一个字符串大小对(作为元组),而不是一个简单的字符串数组.然后:
override func collectionView(_ collectionView: UICollectionView,
cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! MyCell
cell.label.text = self.array[indexPath.row].0
return cell
}
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
return self.array[indexPath.row].1
}
Run Code Online (Sandbox Code Playgroud)
我有同样的问题,单元格使用估计的大小(而不是自动大小),直到滚动.使用Xcode 9.x构建的相同代码在iOS 11和12上运行完美,并且内置在Xcode 10中,它可以在iOS 11上正常运行,但不能在iOS 12上运行.
到目前为止我找到解决此问题的唯一方法是使集合视图的布局无效viewDidAppear
,这可能导致一些跳跃,或者在内部的异步块中viewWillAppear
(不确定该解决方案的可靠性).
override func viewDidLoad() {
super.viewDidLoad()
let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout
layout?.estimatedItemSize = CGSize(width: 50, height: 50)
layout?.itemSize = UICollectionViewFlowLayout.automaticSize
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// The following block also "fixes" the problem without jumpiness after the view has already appeared on screen.
DispatchQueue.main.async {
self.collectionView.collectionViewLayout.invalidateLayout()
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// The following line makes cells size properly in iOS 12.
collectionView.collectionViewLayout.invalidateLayout()
}
Run Code Online (Sandbox Code Playgroud)
小智 6
Cœur的解决方案2 可防止布局在用户面前闪烁或更新.但是,当您旋转设备时,它可能会产生问题.我在viewWillLayoutSubviews中使用变量"shouldInvalidateLayout",并在viewDidAppear中将其设置为false.
private var shouldInvalidateLayout = true
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
shouldInvalidateLayout = false
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
if shouldInvalidateLayout {
collectionView.collectionViewLayout.invalidateLayout()
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
15571 次 |
最近记录: |