我试图得到自我大小UICollectionViewCells工作与自动布局,但我似乎不能让单元格大小自己的内容。我很难理解如何从单元格的contentView内的内容更新单元格的大小。

下面是我尝试过的设置:

自定义UICollectionViewCell,在它的contentView中有一个UITextView。 UITextView的滚动被禁用。 contentView的水平约束是:"H:|[_textView(320)]",也就是说UITextView被固定在单元格的左边,显式宽度为320。 contentView的垂直约束是:"V:|-0-[_textView]",也就是说UITextView固定在单元格的顶部。 UITextView有一个高度约束设置为常数,UITextView报告将适合文本。

下面是单元格背景设置为红色,UITextView背景设置为蓝色时的效果:

我把我一直在GitHub上玩的项目放在这里。


当前回答

解决方案包括3个简单步骤:

启用动态单元格大小

flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize

设置来自collectionView(:cellForItemAt:)的containerview . widthachor .constraint来限制contentView的宽度为collectionView的宽度。

class ViewController: UIViewController, UICollectionViewDataSource {
    ...

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cellId", for: indexPath) as! MultiLineCell
        cell.textView.text = dummyTextMessages[indexPath.row]
        cell.maxWidth = collectionView.frame.width
        return cell
    }

    ...
}

class MultiLineCell: UICollectionViewCell{
    ....

    var maxWidth: CGFloat? {
        didSet {
            guard let maxWidth = maxWidth else {
                return
            }
            containerViewWidthAnchor.constant = maxWidth
            containerViewWidthAnchor.isActive = true
        }
    }

    ....
}

因为你想要启用UITextView的自调整大小,它有一个额外的步骤来;

3.计算和设置高度tanchor。常量的UITextView。

当contentView的宽度被设置时,我们会在didSet的maxWidth中调整UITextView的高度。

UICollectionViewCell Inside job:

var maxWidth: CGFloat? {
    didSet {
        guard let maxWidth = maxWidth else {
            return
        }
        containerViewWidthAnchor.constant = maxWidth
        containerViewWidthAnchor.isActive = true
        
        let sizeToFitIn = CGSize(width: maxWidth, height: CGFloat(MAXFLOAT))
        let newSize = self.textView.sizeThatFits(sizeToFitIn)
        self.textViewHeightContraint.constant = newSize.height
    }
}

这些步骤会让你得到想要的结果。

完整的可运行的要旨

参考:Vadim Bulavin博客文章-集合视图单元格自我调整:一步一步的教程

截图:

其他回答

在Swift 5中,它适用于我。

UICollectionViewFlowLayout:

estimatedItemSize = UICollectionViewFlowLayout.automaticSize

UICollectionViewCell:

(ps:我用的是SnapKit)

class Cell: UICollectionViewCell {
    let customizedContentView = UIView()
    ...
    func layoutAction() {
        contentView.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(customizedContentView)
        customizedContentView.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
    }
}

然后你只需要展开customizedContentView。

如果你实现uicollectionviewdelegatflowlayout方法:

- (CGSize)collectionView:(UICollectionView*)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath*)indexPath

当你调用collectionview performBatchUpdates:completion:时,size height将使用sizeForItemAtIndexPath代替 preferredLayoutAttributesFittingAttributes。

performBatchUpdates:completion的呈现过程将通过preferredLayoutAttributesFittingAttributes方法,但它会忽略您的更改。

编辑11/19/19:对于iOS 13,只使用UICollectionViewCompositionalLayout估计高度。不要浪费时间处理这个坏的API。

在与此斗争了一段时间后,我注意到,如果你不禁用滚动,调整大小对UITextViews不起作用:

let textView = UITextView()
textView.scrollEnabled = false

对于那些尝试一切都没有运气的人来说,这是唯一让它为我工作的东西。 对于单元格内的多行标签,尝试添加以下神奇的行:

label.preferredMaxLayoutWidth = 200

更多信息:点击这里

干杯!

对任何可能有帮助的人,

如果设置了estimatedItemSize,我就会发生严重的崩溃。即使我在numberOfItemsInSection中返回0。因此,单元格本身和它们的自动布局不是导致崩溃的原因……collectionView刚刚崩溃,即使是空的,这只是因为estimatedItemSize被设置为自大小。

在我的例子中,我重新组织了我的项目,从一个包含collectionView的控制器到一个collectionViewController,它工作了。

图。