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

下面是我尝试过的设置:

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

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

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


当前回答

在viewDidLoad()上添加flowLayout override func viewDidLoad() { super.viewDidLoad () if let flowLayout = infoCollection。collectionViewLayout一样吗?UICollectionViewFlowLayout { estimateditemsize = CGSize(宽度:1,高度:1) } } 此外,设置一个UIView为单元的mainContainer,并在其中添加所有必需的视图。 参考这个很棒的,令人兴奋的教程,以获得进一步的参考: 在iOS 9和10中使用自动布局自动调整单元格的UICollectionView

其他回答

解决方案包括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博客文章-集合视图单元格自我调整:一步一步的教程

截图:

内容查看主播奥秘:

在一个奇怪的例子中

    contentView.translatesAutoresizingMaskIntoConstraints = false

不会起作用。在contentView中添加了四个显式的锚,它工作了。

class AnnoyingCell: UICollectionViewCell {
    
    @IBOutlet var word: UILabel!
    
    override init(frame: CGRect) {
        super.init(frame: frame); common() }
    
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder); common() }
    
    private func common() {
        contentView.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            contentView.leftAnchor.constraint(equalTo: leftAnchor),
            contentView.rightAnchor.constraint(equalTo: rightAnchor),
            contentView.topAnchor.constraint(equalTo: topAnchor),
            contentView.bottomAnchor.constraint(equalTo: bottomAnchor)
        ])
    }
}

像往常一样

    estimatedItemSize = UICollectionViewFlowLayout.automaticSize

在你的布局:UICollectionViewFlowLayout

谁知道呢?也许能帮到别人。

信贷

https://www.vadimbulavin.com/collection-view-cells-self-sizing/

无意中发现了这个技巧——在其他1000篇文章中从未见过。

我做了一个动态单元格高度的集合视图。这里是git中心回购。

并且,挖掘出为什么preferredLayoutAttributesFittingAttributes被调用不止一次。实际上,它至少会被调用3次。

控制台日志图:

第一preferredLayoutAttributesFittingAttributes:

(lldb) po layoutAttributes
<UICollectionViewLayoutAttributes: 0x7fa405c290e0> index path: (<NSIndexPath:    0xc000000000000016> 
{length = 2, path = 0 - 0}); frame = (15 12; 384 57.5); 

(lldb) po self.collectionView
<UICollectionView: 0x7fa40606c800; frame = (0 57.6667; 384 0);

layoutAttributes.frame.size.height的当前状态是57.5。

第二preferredLayoutAttributesFittingAttributes:

(lldb) po layoutAttributes
<UICollectionViewLayoutAttributes: 0x7fa405c16370> index path: (<NSIndexPath: 0xc000000000000016> 
{length = 2, path = 0 - 0}); frame = (15 12; 384 534.5); 

(lldb) po self.collectionView
<UICollectionView: 0x7fa40606c800; frame = (0 57.6667; 384 0);

单元格帧高度变为534.5,正如我们预期的那样。但是集合视图高度仍然为0。

3日preferredLayoutAttributesFittingAttributes:

(lldb) po layoutAttributes
<UICollectionViewLayoutAttributes: 0x7fa403d516a0> index path: (<NSIndexPath: 0xc000000000000016> 
{length = 2, path = 0 - 0}); frame = (15 12; 384 534.5); 

(lldb) po self.collectionView
<UICollectionView: 0x7fa40606c800; frame = (0 57.6667; 384 477);

您可以看到集合视图的高度从0更改为477。

行为类似于handle scroll:

1. Before self-sizing cell

2. Validated self-sizing cell again after other cells recalculated.

3. Did changed self-sizing cell

一开始,我以为这个方法只调用一次。所以我编码如下:

CGRect frame = layoutAttributes.frame;
frame.size.height = frame.size.height + self.collectionView.contentSize.height;
UICollectionViewLayoutAttributes* newAttributes = [layoutAttributes copy];
newAttributes.frame = frame;
return newAttributes;

这条线:

frame.size.height = frame.size.height + self.collectionView.contentSize.height;

将导致系统调用无限循环和应用程序崩溃。

任何大小改变,它将验证所有单元格的preferredLayoutAttributesFittingAttributes一次又一次,直到每个单元格的位置(即帧)不再改变。

对丹尼尔·加拉斯科的回答做了一些关键的修改,解决了我所有的问题。不幸的是,我还没有足够的声誉来直接评论。

在第一步,当使用自动布局时,简单地添加一个单亲UIView到单元格。单元格内的所有东西都必须是父视图的子视图。这解决了我所有的问题。虽然Xcode会自动为UITableViewCells添加这个,但它不会(但应该)为UICollectionViewCells添加这个。根据文件:

要配置单元格的外观,请在contentView属性的视图中添加将数据项的内容作为子视图显示所需的视图。不要直接向单元格本身添加子视图。

然后完全跳过步骤3。这是不需要的。

除了以上答案,

只要确保你将UICollectionViewFlowLayout的estimatedItemSize属性设置为某个大小,而不实现sizeForItem:atIndexPath委托方法。

就是这样。