可变宽度和宽度使用带故事板的AutoLayout(不带XIB)的UICollectionViewCell高度

时间:2015-06-23 09:07:53

标签: ios uicollectionview autolayout storyboard height

这是应用程序中的一个设计问题,它使用AutoLayout,UICollectionView和UICollectionViewCell,它可以自动调整宽度和宽度。高度取决于AutoLayout约束及其内容(某些文本)。

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

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

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

解决这种情况的最接近的方法似乎是将单元格的定义复制到视图层次结构中,让自动布局自动调整大小“单元格”(就像单元格具有与父集合视图相同的宽度),因此app可以配置单元格具体内容并计算其大小。由于资源重复,这绝对不应该是修复它的唯一方法。

所有这一切都与将UILabel.preferredMaxLayoutWidth设置为某​​个值相关联,该值应该是可自动布局可控制的(不是硬编码的),这可能取决于屏幕宽度&高度或至少通过自动布局约束定义设置,因此应用程序可以获得多线UILabel内在大小计算。

我不想实例化XIB文件中的单元格,因为Storyboard应该是今天的行业标准,我希望尽可能减少对代码的干预。

编辑:

下面列出了无法运行的基本代码。因此,仅实例化变量cellProbe(未使用)会使应用程序崩溃。没有那个电话,应用程序运行顺畅。

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
    }
}

3 个答案:

答案 0 :(得分:12)

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

相反,您需要在estimatedItemSize中设置一个大小,方法是将其设置为CGSizeZero以外的值,告诉布局您还不知道确切的大小。然后布局将询问每个单元格的大小,并在需要时进行计算。

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

答案 1 :(得分:2)

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

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

in

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

正确的方法是创建一个用于高度计算的局部静态单元格,如自定义单元格的类方法

+ (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是创建自定义单元格视图的最佳方式,包括tableViewCell和CollectionViewCell

答案 2 :(得分:2)

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

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