我正在尝试使用自动布局来调整 UICollectionViewCells
的大小,但我似乎无法让单元格根据内容调整大小。我无法理解单元格的大小是如何从单元格的 contentView 中的内容更新的。
这是我尝试过的设置:
UICollectionViewCell
在其内容 View 中带有 UITextView
。 UITextView
的滚动被禁用。 UITextView
固定在单元格左侧,显式宽度为 320。 0x29191222133UITextView
固定在单元格的顶部。 UITextView
的高度约束设置为常量,UITextView
报告将适合文本。 这是将单元格背景设置为红色,将
UITextView
背景设置为蓝色时的样子:
我把我一直在玩的项目放在 GitHub here 上。
最佳答案
为 Swift 5 更新preferredLayoutAttributesFittingAttributes
重命名为 preferredLayoutAttributesFitting
并使用自动调整大小
为 Swift 4 更新systemLayoutSizeFittingSize
重命名为 systemLayoutSizeFitting
针对 iOS 9 更新
在看到我的 GitHub 解决方案在 iOS 9 下崩溃后,我终于有时间全面调查这个问题。我现在已经更新了 repo 以包含几个不同配置的示例,用于自定大小的单元格。我的结论是,自定尺寸单元在理论上很棒,但在实践中却很困惑。使用自定大小单元格时要小心。
TL;DR
查看我的 GitHub project
仅流布局支持自调整单元格,因此请确保这就是您正在使用的。
您需要设置两件事才能使自定大小单元格工作。
1. 在 estimatedItemSize
上设置 UICollectionViewFlowLayout
设置 estimatedItemSize
属性后,流布局本质上将变得动态。
self.flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
2. 添加对单元子类大小调整的支持
这有 2 种口味;自动布局 或 自定义覆盖
preferredLayoutAttributesFittingAttributes
。使用自动布局创建和配置单元格
我不会详细讨论这个,因为有一个关于为单元配置约束的精彩 SO post。请注意 Xcode 6 broke 与 iOS 7 相关的一堆东西,因此,如果您支持 iOS 7,则需要执行诸如确保在单元格的 contentView 上设置 autoresizingMask 以及将 contentView 的边界设置为单元格时单元格的边界已加载(即
awakeFromNib
)。您需要注意的是,您的单元格需要比表 View 单元格受到更严格的约束。例如,如果您希望您的宽度是动态的,那么您的单元格需要一个高度约束。同样,如果您希望高度是动态的,那么您将需要对单元格进行宽度约束。
在您的自定义单元格中实现
preferredLayoutAttributesFittingAttributes
调用此函数时,您的 View 已经配置了内容(即
cellForItem
已被调用)。假设您的约束已适当设置,您可以有这样的实现://forces the system to do one layout pass
var isHeightCalculated: Bool = false
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
//Exhibit A - We need to cache our calculation to prevent a crash.
if !isHeightCalculated {
setNeedsLayout()
layoutIfNeeded()
let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
var newFrame = layoutAttributes.frame
newFrame.size.width = CGFloat(ceilf(Float(size.width)))
layoutAttributes.frame = newFrame
isHeightCalculated = true
}
return layoutAttributes
}
注意 在 iOS 9 上,行为发生了一些变化,如果您不小心,可能会导致您的实现崩溃(请参阅更多信息 here )。当您实现
preferredLayoutAttributesFittingAttributes
时,您需要确保只更改一次布局属性的框架。如果您不这样做,布局将无限期地调用您的实现并最终崩溃。一种解决方案是在您的单元格中缓存计算出的大小,并在您重用单元格或更改其内容时使其无效,就像我对 isHeightCalculated
属性所做的那样。体验您的布局
此时,您的 collectionView 中应该有“功能正常”的动态单元格。在我的测试中,我还没有找到足够的开箱即用的解决方案,所以如果你有的话,请随时发表评论。仍然感觉
UITableView
赢得了动态调整大小恕我直言。注意事项
请注意,如果您使用原型(prototype)单元格来计算estimatedItemSize - 如果您的 XIB uses size classes 会中断。这样做的原因是,当您从 XIB 加载单元格时,其大小类将配置为
Undefined
。这只会在 iOS 8 及更高版本上被打破,因为在 iOS 7 上,大小类将根据设备加载(iPad = 常规-任意,iPhone = 紧凑-任意)。您可以设置estimatedItemSize而不加载XIB,或者您可以从XIB加载单元格,将其添加到collectionView(这将设置traitCollection),执行布局,然后将其从superview中删除。或者,您也可以让您的单元格覆盖 traitCollection
getter 并返回适当的特征。由你决定。如果我错过了什么,请告诉我,希望我有所帮助,祝您编码愉快
关于ios - 具有自动布局的 UICollectionView 自动调整单元格大小,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25895311/