使用AutoLayout与Storyboard(不带XIB)的UICollectionViewCell的宽度和高度可变

以下是使用AutoLayout,UICollectionView和UICollectionViewCell的应用程序中的一个devise问题,该问题根据AutoLayout约束及其内容(某些文本)自动调整宽度和高度。

这是一个UITableView列表,每个单元格都有自己的宽度和高度,根据其内容分别针对每一行进行计算。 它更像是在应用程序(或WhatsUp)中构build的iOS消息。

很显然,应用程序应该使用func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize

问题是,在该方法,应用程序无法调用func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCelldequeueReusableCellWithReuseIdentifier(identifier: String, forIndexPath indexPath: NSIndexPath!) -> AnyObject实例化单元格,填充特定的内容并计算其宽度和高度。 试图这样做会导致无限recursion调用或其他types的应用程序崩溃(至less在iOS 8.3中)。

解决这种情况的最接近的方法似乎是将单元格的定义复制到视图层次结构中,以使自动布局自动调整“单元格”(如单元格具有与父集合视图相同的宽度),所以应用程序可以configuration具有特定内容的单元格,计算其大小。 这肯定不是解决它的唯一方法,因为资源重复。

所有这一切都与设置UILabel.preferredMaxLayoutWidth到一些值应该是自动布局可控(非硬编码),可能取决于屏幕宽度和高度,或至less由自动布局约束定义设置,所以应用程序可以得到多行UILabel内在大小计算。

我不想从XIB文件中实例化单元格,因为Storyboards应该是当今的行业标准,而且我希望对代码有更less的干预。

编辑:

下面列出了不能运行的基本代码。 所以只有实例化variablescellProbe(未使用)崩溃的应用程序。 没有这个电话,应用程序运行顺利。

 var onceToken: dispatch_once_t = 0 class ViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout { override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return 1 } func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize { dispatch_once(&onceToken) { let cellProbe = collectionView.dequeueReusableCellWithReuseIdentifier("first", forIndexPath: NSIndexPath(forRow: 0, inSection: 0)) as! UICollectionViewCell } return CGSize(width: 200,height: 50) } override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCellWithReuseIdentifier("first", forIndexPath: NSIndexPath(forRow: 0, inSection: 0)) as! UICollectionViewCell return cell } } 

如果使用约束,则不需要为每个单元格设置大小。 所以你应该删除你的委托方法func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize

相反,您需要通过将此值设置为CGSizeZero以外的值来设置estimatedItemSize的大小,您将告知布局您还不知道确切的大小。 然后布局会询问每个单元格的大小,并在需要时计算。

 let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout layout.estimatedItemSize = someReasonableEstimatedSize() 

就像使用“自动布局”dynamic调整“表格视图”单元高度时一样,您不需要调用

func tableView(_ tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell

optional func tableView(_ tableView: UITableView, heightForRowAtIndexPath indexPath: NSIndexPath) -> CGFloat

正确的方法是创build一个本地静态单元格,用于高度计算,就像自定义单元格的类方法一样

 + (CGFloat)cellHeightForContent:(id)content tableView:(UITableView *)tableView { static CustomCell *cell; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ cell = [tableView dequeueReusableCellWithIdentifier:[CustomCell cellIdentifier]]; }); Item *item = (Item *)content; configureBasicCell(cell, item); [cell setNeedsLayout]; [cell layoutIfNeeded]; CGSize size = [cell.contentView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]; return size.height + 1.0f; // Add 1.0f for the cell separator height } 

我严重怀疑故事板是一些行业标准。 xib是创build类似view的自定义单元格的最佳方式,包括tableViewCell和CollectionViewCell

要dynamic计算CollectionView单元格的大小,只需将stream布局属性设置为任意值:

  let flowLayout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout flowLayout.estimatedItemSize = CGSize(width: 0, height: 0)