我试图让自调整大小的UICollectionViewCells
与自动布局一起工作,但我似乎无法让单元格根据内容调整自己的大小。我很难理解单元格的大小是如何根据单元格的contentView中的内容更新的。
下面是我尝试过的设置:
contentView.
UITextView
的UITextView
自定义UICollectionViewCell
被禁用。
UITextView
固定在单元格左侧,显式宽度为320。
UITextView
。
UITextView
的高度约束设置为一个常量,UITextView
报告将适合该常量。下面是单元格背景设置为红色,UITextView
背景设置为蓝色时的外观:
我把我一直在玩的项目放在GitHub here上。
发布于 2014-09-17 17:04:24
这个答案在iOS 14中已经过时了,因为它增加了组合布局。请考虑更新new API
针对Swift 5更新
preferredLayoutAttributesFittingAttributes
已重命名为preferredLayoutAttributesFitting
并使用自动调整大小
针对Swift 4更新
systemLayoutSizeFittingSize
已重命名为systemLayoutSizeFitting
针对iOS 9进行了更新
在看到我的GitHub解决方案在iOS 9下崩溃后,我终于有时间全面调查这个问题了。我现在已经更新了存储库,包含了几个不同配置的示例,用于自调整单元大小。我的结论是,自调整单元格的大小在理论上是很好的,但在实践中却很混乱。在继续调整单元格大小时需要注意的一点是。
TL;DR
查看我的GitHub project
只有流式布局才支持自调整单元格大小,因此请确保您使用的是自调整大小的单元格。
要使自调整大小的单元格正常工作,需要进行两项设置。
#1.在UICollectionViewFlowLayout
上设置estimatedItemSize
设置estimatedItemSize
属性后,流布局本质上将变为动态布局。
self.flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
#2.添加对计算单元格子类大小的支持
这有两种风格:自动布局或preferredLayoutAttributesFittingAttributes
的自定义覆盖。
使用自动布局创建和配置单元格
我不会在中详细介绍这一点,因为有一个关于为单元配置约束的出色的SO post。只需注意在iOS 7中Xcode 6 broke一大堆东西,所以,如果你支持iOS 7,你将需要做一些事情,比如确保autoresizingMask设置在单元格的contentView上,以及确保contentView的边界在加载单元格时设置为单元格的边界(即awakeFromNib
)。
您需要注意的是,您的单元格需要比表视图单元格更严格的约束。例如,如果您希望宽度是动态的,那么您的单元格就需要高度约束。同样,如果您希望高度是动态的,那么您需要对单元格进行宽度约束。
在自定义单元中实现preferredLayoutAttributesFittingAttributes
当调用此函数时,您的视图已经配置了内容(即调用了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
赢得了动态大小之战。
##Caveats请注意,如果您使用原型单元来计算estimatedItemSize -如果您的XIB uses size classes将中断。这样做的原因是,当您从XIB加载单元时,它的size类将配置为Undefined
。这只会在iOS 8和更高版本上被破坏,因为在iOS 7上,size类将基于设备加载(iPad = Regular-Any,iPhone = Compact-Any)。您可以在不加载XIB的情况下设置estimatedItemSize,也可以从XIB加载单元,将其添加到collectionView (这将设置traitCollection),执行布局,然后将其从superview中删除。或者,您也可以让您的单元覆盖traitCollection
获取方法并返回适当的特征。由你决定。
如果我遗漏了什么,请让我知道,希望我能帮上忙,祝你编码好运
发布于 2017-03-22 10:26:43
在iOS10中,有一个名为UICollectionViewFlowLayout.automaticSize
(以前称为UICollectionViewFlowLayoutAutomaticSize
)的新常量,因此:
self.flowLayout.estimatedItemSize = CGSize(width: 100, height: 100)
您可以使用以下命令:
self.flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
它具有更好的性能,特别是当集合视图中的单元格具有恒定宽度时。
访问流程布局:
override func viewDidLoad() {
super.viewDidLoad()
if let flowLayout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
}
}
Swift 5更新:
override func viewDidLoad() {
super.viewDidLoad()
if let flowLayout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
}
}
发布于 2015-07-07 21:35:26
对Daniel Galasko's answer的一些关键更改解决了我的所有问题。不幸的是,我还没有足够的名气直接发表评论。
在步骤1中,当使用自动布局时,只需将单个父UIView添加到单元格。单元格中的所有内容都必须是父视图的子视图。这解决了我所有的问题。虽然Xcode会自动为UITableViewCells添加此功能,但它不会(但应该)为UICollectionViewCells添加此功能。根据docs的说法:
若要配置单元格的外观,请将将数据项内容作为子视图呈现所需的视图添加到contentView属性中的视图中。不要直接向单元格本身添加子视图。
然后完全跳过步骤3。它不是必需的。
https://stackoverflow.com/questions/25895311
复制相似问题