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

下面是我尝试过的设置:

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

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

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


当前回答

在iOS 10+中,这是一个非常简单的2步过程。

Ensure that all your cell contents are placed within a single UIView (or inside a descendant of UIView like UIStackView which simplifies autolayout a lot). Just like with dynamically resizing UITableViewCells, the whole view hierarchy needs to have constraints configured, from the outermost container to the innermost view. That includes constraints between the UICollectionViewCell and the immediate childview Instruct the flowlayout of your UICollectionView to size automatically yourFlowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize

其他回答

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

更新更多信息:

If you use flowLayout.estimatedItemSize, suggest use iOS8.3 later version. Before iOS8.3, it will crash [super layoutAttributesForElementsInRect:rect];. The error message is *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil' Second, in iOS8.x version, flowLayout.estimatedItemSize will cause different section inset setting did not work. i.e. function: (UIEdgeInsets)collectionView:layout:insetForSectionAtIndex:.

如果你实现uicollectionviewdelegatflowlayout方法:

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

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

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

我做了一个动态单元格高度的集合视图。这里是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一次又一次,直到每个单元格的位置(即帧)不再改变。

内容查看主播奥秘:

在一个奇怪的例子中

    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篇文章中从未见过。