这个答案在IOS 14中已经过时,因为增加了构图布局.请考虑更新new API
Updated for Swift 5
preferredLayoutAttributesFittingAttributes
重命名为preferredLayoutAttributesFitting
并使用自动调整大小
Updated for Swift 4
systemLayoutSizeFittingSize
重命名为systemLayoutSizeFitting
Updated for iOS 9
在看到我的GitHub解决方案在iOS9下崩溃后,我终于有时间全面调查这个问题了.我现在已经更新了repo,包括了几个用于自调整单元大小的不同配置的示例.我的结论是,自调整细胞大小在理论上是伟大的,但在实践中却是混乱的.在继续调整单元格大小时需要注意的一点是.
TL;DR个
看看我的GitHub project美元
只有流布局才支持自调整单元格大小,因此请确保您使用的是自调整大小的单元格.
要使单元格自调整大小正常工作,需要设置两项内容.
#1.将estimatedItemSize
设置为UICollectionViewFlowLayout
一旦设置了estimatedItemSize
属性,流布局本质上就会变成动态的.
self.flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
#2.添加对计算单元格子类大小的支持
这有两种口味;自动布局or自定义覆盖preferredLayoutAttributesFittingAttributes
.
使用自动布局创建和配置单元格
我不会详细介绍这一点,因为有关于为单元配置约束的精彩的SO post篇文章.只需小心Xcode 6 broke和iOS7中的一堆东西,所以,如果你支持iOS7,你将需要做一些事情,比如确保在单元格的contentView上设置了autosizingMask,并且在加载单元格时(即awakeFromNib
)将contentView的边界设置为单元格的边界.
您需要注意的是,您的单元格需要比表视图单元格受到更严格的约束.例如,如果希望宽度是动态的,则单元格需要高度约束.同样,如果希望高度是动态的,则需要对单元格进行宽度约束.
Implement preferredLayoutAttributesFittingAttributes
in your custom cell
当调用此函数时,您的视图已经配置了内容(即调用了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
}
NOTE在iOS9上,行为稍有改变,如果您一不小心,可能会导致您的实现崩溃(参见更多here页).在实现preferredLayoutAttributesFittingAttributes
时,您需要确保只更改布局属性的框架一次.如果您不这样做,布局将无限期地调用您的实现,最终导致崩溃.一种解决方案是将计算出的大小缓存在单元格中,并在任何时候重用单元格或更改其内容时使其无效,就像我对isHeightCalculated
属性所做的那样.
体验您的布局
此时,您的集合视图中应该有"正常运行"的动态单元格.在我的测试过程中,我还没有发现足够的开箱即用的解决方案,所以如果您有,请随意 comments .它仍然感觉UITableView
赢得了动态大小之战IMHO.
##注意事项
请非常注意,如果您使用原型单元格来计算EstiatedItemSize-如果您的值为XIB uses size classes,这将中断.这样做的原因是,当您从XIB加载单元时,其Size类将配置为Undefined
.这只会在iOS8和更高版本上被打破,因为在iOS7上,Size类将根据设备加载(iPad=Regular-Any,iPhone=Compact-Any).您可以在不加载XIB的情况下设置EstiatedItemSize,也可以从XIB加载单元格,将其添加到集合视图(这将设置traitCollection),执行布局,然后将其从SuperView中删除.或者,您也可以让您的计算单元覆盖traitCollection
获取函数并返回适当的特征.由你决定.
如果我错过了什么,请告诉我,希望我能帮助你,祝你好运