UICollectionView自动调整大小的单元格


207

我正在尝试UICollectionViewCells使用“自动版式” 调整大小,但似乎无法使单元格自行调整大小以适应内容。我无法理解如何从单元的contentView内部内容更新单元的大小。

这是我尝试过的设置:

  • 在其contentView中UICollectionViewCell使用进行自定义UITextView
  • 滚动到UITextView禁用。
  • contentView的水平约束为:“ H:| [_textView(320)]”,即,UITextView以固定的宽度320固定在单元格的左侧。
  • contentView的垂直约束为:“ V:| -0-[_ textView]”,即UITextView固定在单元格顶部。
  • UITextView高度限制设置为一个常量,UITextView报告将适合文本。

单元格背景设置为红色,UITextView背景设置为蓝色的外观如下: 单元格背景为红色,UITextView背景为蓝色

我把我已经在GitHub上玩的项目在这里


您是否正在实现sizeForItemAtIndexPath方法?
Daniel Galasko 2014年

@DanielGalasko我不是。我的理解是,iOS 8中新的自调整大小单元功能不再需要您这样做。
rawbee 2014年

不确定从何处获得该信息,但仍需要查看WWDC摘录asciiwwdc.com/2014/sessions/226
Daniel Galasko 2014年

但这又取决于您的用例,请确保您实现
EstimatedItemSize

1
2019年
务必

Answers:


309

已为Swift 5更新

preferredLayoutAttributesFittingAttributes重命名preferredLayoutAttributesFitting并使用自动调整大小


为Swift 4更新

systemLayoutSizeFittingSize 重命名为 systemLayoutSizeFitting


已针对iOS 9更新

在看到我的GitHub解决方案在iOS 9下中断后,我终于有时间充分研究此问题。现在,我已更新该存储库,以包含几个用于自定义大小单元的不同配置的示例。我的结论是,自动调整大小的单元格在理论上很棒,但在实践中却很凌乱。在进行自定尺寸的细胞时要小心。

TL; DR

查看我的GitHub项目


自定义单元格仅受流布局支持,因此请确保这是您所使用的。

要使自定义大小的单元正常工作,需要设置两件事。

1. estimatedItemSize开始UICollectionViewFlowLayout

设置estimatedItemSize属性后,流布局本质上将变得动态。

self.flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize

2.添加对单元子类大小调整的支持

这有2种口味;自动版式或的自定义替代preferredLayoutAttributesFittingAttributes

使用自动布局创建和配置单元格

我不会详细介绍这一点,因为有一篇出色的SO post关于为单元配置约束。只是要警惕Xcode 6在iOS 7上破坏了很多东西,因此,如果您支持iOS 7,则需要做一些事情,例如确保在单元格的contentView上设置了autoresizingMask,并且将contentView的边界设置为单元格的边界。单元已加载(即awakeFromNib)。

您需要了解的事情是,与表格视图单元格相比,您的单元格需要受到更严格的约束。例如,如果您希望宽度是动态的,则您的单元格需要高度限制。同样,如果希望高度是动态的,则需要对单元格设置宽度约束。

preferredLayoutAttributesFittingAttributes在您的自定义单元中实施

调用此函数时,您的视图已经配置了内容(cellForItem即已被调用)。假设已经适当设置了约束,则可以实现如下所示的实现:

//forces the system to do one layout pass
var isHeightCalculated: Bool = false

override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
    //Exhibit A - We need to cache our calculation to prevent a crash.
    if !isHeightCalculated {
        setNeedsLayout()
        layoutIfNeeded()
        let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
        var newFrame = layoutAttributes.frame
        newFrame.size.width = CGFloat(ceilf(Float(size.width)))
        layoutAttributes.frame = newFrame
        isHeightCalculated = true
    }
    return layoutAttributes
}

注意在iOS 9上,如果不小心,行为会有所改变,可能会导致实现崩溃(请参阅此处的更多信息)。实施时preferredLayoutAttributesFittingAttributes,需要确保仅更改布局属性的框架一次。如果不这样做,则布局将无限期地调用您的实现,并最终崩溃。一种解决方案是将计算出的大小缓存在您的单元格中,并在您重复使用该单元格或更改其内容时使此无效,就像我对isHeightCalculated属性所做的那样。

体验您的布局

此时,您应该在collectionView中具有“运行中”的动态单元格。在测试期间,我还没有发现开箱即用的解决方案就足够了,因此如有需要,请随时发表评论。仍然感觉像UITableView赢得动态大小恕我直言的战斗。

注意事项

请注意,如果您使用原型单元格来计算estimatedItemSize,那么当您的XIB使用size类时,这将会中断。原因是,当您从XIB加载单元时,其大小类将配置为Undefined。这只会在iOS 8及更高版本上被打破,因为在iOS 7上将根据设备加载大小类(iPad =常规-任何,iPhone =紧凑-任何)。您可以在不加载XIB的情况下设置estimatedItemSize,也可以从XIB加载单元,将其添加到collectionView(这将设置traitCollection),执行布局,然后将其从超级视图中删除。或者,您也可以使单元格覆盖traitCollection吸气剂并返回适当的特征。由你决定。

让我知道我是否错过任何事情,希望能对我有所帮助,祝您好运



2
我正在尝试用流布局实现相同的功能,但是当我将它以更新的大小返回newFrame时,布局似乎并没有重新计算y位置,这些位置仍然基于estimateSize中的高度。少了什么东西?
安娜2014年

@anna您在布局上调用invalidateLayout吗?
Daniel Galasko

1
啊,发现差异,您将估计高度设置得很高(400),而我却做了最小值(44)。有帮助。但是,除非您一直滚动浏览,否则contentSize似乎仍然无法正确设置,因此仍然不是很有用。顺便说一句,我将UITextView更改为UILabel,具有相同的行为。
安娜2014年

17
这似乎在iOS 9 GM上从根本上打破了。设置estimatedItemSize会导致崩溃-自动布局尝试处理UICollectionViewCell的方式似乎存在一些巨大的错误。
Wes Campaigne

3
遇到类似问题,有人找到解决方法了吗?
托尼

47

在iOS10中,有一个新的常量UICollectionViewFlowLayout.automaticSize(以前称为UICollectionViewFlowLayoutAutomaticSize),因此:

self.flowLayout.estimatedItemSize = CGSize(width: 100, height: 100)

您可以使用此:

self.flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize

它具有更好的性能,尤其是当您的集合视图中的单元具有恒定宽度时

访问流布局:

override func viewDidLoad() {
   super.viewDidLoad()

   if let flowLayout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
      flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
   }
}

Swift 5更新:

override func viewDidLoad() {
   super.viewDidLoad()

   if let flowLayout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
      flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
    }
}

8
您在哪里设置?在viewdidload?您如何处理flowlayout?
UKDataGeek '17

1
我设法实现了这一点-但它有一个奇怪的行为,如果有一个单元格,它将使其居中。这是关于它的堆栈溢出问题-我
难过吗

1
您可以通过collectionViews访问流布局collectionViewLayout,只是检查它的类型UICollectionViewFlowLayout
d4Rk

4
它使我的细胞非常小,无用
user924 '19

44

丹尼尔·加拉斯科(Daniel Galasko)的答案进行了一些关键更改,解决了我所有的问题。不幸的是,我没有足够的声誉直接发表评论。

在第1步中,使用“自动布局”时,只需将单个父UIView添加到单元格。单元格中的所有内容都必须是父级的子视图。那回答了我所有的问题。虽然Xcode会自动为UITableViewCells添加此代码,但不会(但应该)为UICollectionViewCells添加它。根据文档

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

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


1
有趣; 这是专门针对Xibs的,但是还是谢谢,将尝试与Github项目混为一谈,看看我是否可以复制。也许将答案分为
Xib

很有帮助 。谢谢!
ProblemSlover

2
iOS 9,Xcode7。单元在情节提要中进行原型化,设置自定义子类。尝试创建一个名为的属性contentView,Xcode抱怨它与现有属性冲突。尝试向其中添加子视图self.contentView并为其设置约束,然后应用崩溃。
Nicolas Miari

@NicolasMiari我不知道如何以编程方式执行此操作,我的解决方案实际上只是在XIB中添加一个uiview,所有内容都放在其中。您无需创建属性或其他任何内容。
马特·考拉

我面临与@NicolasMiari相同的问题。当我为在iOS 9 / Xcode 7上具有自动布局约束的情节提要中原型制作的单元格设置估算的ContentSize时,应用程序崩溃,其中包含不良的访问异常并且没有有用的堆栈跟踪
wasabi

34

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

  1. 确保将所有单元格内容放置在单个UIView中(或放置在UIView的后代中,例如UIStackView,这大大简化了自动布局)。就像动态调整UITableViewCells的大小一样,从最外面的容器到最里面的视图,整个视图层次结构都需要配置约束。其中包括UICollectionViewCell和直接子视图之间的约束

  2. 指示UICollectionView的布局自动调整大小

    yourFlowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize

我很好奇,如何将单元格内容包装在UIView中使自动版式的性能更好?我以为它会在层次更浅的情况下更好地执行?
James Heald

1
我没有提到性能,只是简单。仅当您的约束在左右之间以及上下之间始终存在约束时,才能自动调整单元格的大小。当所有视图都包装在一个容器中时,最容易实现。如果该容器是UIStackView,则比起它是UIView的其他任何子代更容易。
Marmoy

您能否告诉我如何为UICollectionViewFlowLayoutAutomaticSize设置高度常数(例如将高度设置为25,宽度将自动更改)。
郑格车

使用Swift 4.1,Xcode告诉我UICollectionViewFlowLayout.automaticSize已重命名为UICollectionViewFlowLayoutAutomaticSize
LinusGeffarth '19

14
  1. 在viewDidLoad()上添加flowLayout

    override func viewDidLoad() {
        super.viewDidLoad() 
        if let flowLayout = infoCollection.collectionViewLayout as? UICollectionViewFlowLayout {
            flowLayout.estimatedItemSize = CGSize(width: 1, height:1)
        }
    }
  2. 另外,将UIView设置为您的单元的mainContainer并在其中添加所有必需的视图。

  3. 请参阅此功能强大,令人赞叹的教程以获取更多参考: iOS 9和10中具有使用自动布局自动调整单元格大小的UICollectionView


11

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

经过一段时间的努力之后,我注意到如果不禁用滚动,则调整大小不适用于UITextViews:

let textView = UITextView()
textView.scrollEnabled = false

当我尝试滚动时,集合视图单元格不平滑。您对此有任何解决方案吗?
Sathish Kumar Gurunathan

6

contentView锚的奥秘:

在一个奇怪的情况下

    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

YourLayout: UICollectionViewFlowLayout

谁知道?可能会帮助某人。

信用

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

偶然发现那里的尖端-在所有1000篇文章中从未见过。


3

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

并且,找出为什么preferredLayoutAttributesFittingAttributes被多次调用的原因。实际上,它将至少被调用3次。

控制台日志图片: 在此处输入图片说明

1st 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,正如我们的预期。但是,集合视图的高度仍为零。

第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

该行为类似于句柄滚动:

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,直到每个单元格的位置(即帧)不再变化为止。


2

除了上述答案之外,

只要确保你设置estimatedItemSize财产UICollectionViewFlowLayout一些大小和执行sizeForItem:atIndexPath委托方法。

而已。


1

如果实现UICollectionViewDelegateFlowLayout方法:

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

呼叫时collectionview performBatchUpdates:completion:,将使用高度sizeForItemAtIndexPath代替 preferredLayoutAttributesFittingAttributes

的渲染过程performBatchUpdates:completion将通过该方法,preferredLayoutAttributesFittingAttributes但会忽略您的更改。


我已经看到了这种不当行为,但仅在估计大小为零时才看到。您确定要设置估算尺寸吗?
dgatwood '17

1

对于可能会帮助的人

如果estimatedItemSize设置的话,我会遇到令人讨厌的崩溃。即使我在中返回0 numberOfItemsInSection。因此,单元格本身及其自动布局并不是崩溃的原因... collectionView只是崩溃了,即使是空的,也仅仅是因为estimatedItemSize它设置为自动调整大小。

在我的情况下,我将项目从包含collectionView的控制器重组为collectionViewController,并且它可以正常工作。

去搞清楚。


1
尝试调用collectionView.collectionViewLayout.invalidateLayout()collectionView.reloadData()
chengsam

对于ios10及以下版本,请添加此代码`覆盖func viewWillLayoutSubviews(){super.viewWillLayoutSubviews()如果#available(iOS 11.0,*){} else {mainCollectionView.collectionViewLayout.invalidateLayout()}}`
Marosdee Uma,

1

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

label.preferredMaxLayoutWidth = 200

更多信息:这里

干杯!


0

上面的示例方法无法编译。这是更正的版本(但未经测试是否有效。)

override func preferredLayoutAttributesFittingAttributes(layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes 
{
    let attr: UICollectionViewLayoutAttributes = layoutAttributes.copy() as! UICollectionViewLayoutAttributes

    var newFrame = attr.frame
    self.frame = newFrame

    self.setNeedsLayout()
    self.layoutIfNeeded()

    let desiredHeight: CGFloat = self.contentView.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize).height
    newFrame.size.height = desiredHeight
    attr.frame = newFrame
    return attr
}

0

更新更多信息:

  • 如果使用flowLayout.estimatedItemSize,建议使用iOS8.3更高版本。在iOS8.3之前,它将崩溃[super layoutAttributesForElementsInRect:rect];。错误消息是

    *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[__NSArrayM insertObject:atIndex:]: object cannot be nil'

  • 其次,在iOS8.x版本中,flowLayout.estimatedItemSize会导致不同部分的inset设置不起作用。即功能:(UIEdgeInsets)collectionView:layout:insetForSectionAtIndex:


0

该解决方案包括4个重要步骤:

  1. 启用动态单元大小调整

flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize

  1. 明确启用自动布局并固定contentView到单元格的边缘,因为会contentView阻止自动调整大小,因为它没有启用自动布局。
class MultiLineCell: UICollectionViewCell{

    private var textViewHeightContraint: NSLayoutConstraint!

    override init(frame: CGRect) {
        super.init(frame: frame)
        backgroundColor = .cyan
        contentView.translatesAutoresizingMaskIntoConstraints = false
        contentViewWidthAnchor = contentView.widthAnchor.constraint(equalToConstant: 0)

        NSLayoutConstraint.activate([
            contentView.leadingAnchor.constraint(equalTo: leadingAnchor),
            contentView.topAnchor.constraint(equalTo: topAnchor),
            contentView.trailingAnchor.constraint(equalTo: trailingAnchor),
            contentView.bottomAnchor.constraint(equalTo: bottomAnchor),
        ])
    } 
    ...
}
  1. 设置contentView.widthAnchor.constraint为,collectionView(:cellForItemAt:)以将contentView 的宽度限制为collectionView的宽度。

它发生如下:我们将在的方法中将单元格的maxWidth变量设置为CollectionView的宽度,collectionView(:cellForItemAt:)maxWidthdidSet方法中,将widthAnchor.constant设置为maxWidth。

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
            }
            contentViewWidthAnchor.constant = maxWidth
            contentViewWidthAnchor.isActive = true
        }
    }

    ....
}

由于您要启用UITextView的自动调整大小,因此它还有一个额外的步骤:

4.计算并设置UITextView的heightAnchor.constant。

因此,无论何时设置contentView的宽度,我们都将沿didSetof 调整UITextView的高度maxWidth

在UICollectionViewCell内部:

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

        let sizeToFitIn = CGSize(width: maxWidth, height: CGFloat(MAXFLOAT))
        let newSize = self.textView.sizeThatFits(sizeToFitIn)
        self.textViewHeightContraint.constant = newSize.height
    }
}

这些步骤将为您提供所需的结果。这是一个完整的可运行要点

感谢Vadim Bulavin的博客文章清晰而有启发性- 集合视图单元格的自我调整:分步教程


-2

我尝试使用,estimatedItemSize但是如果插入和删除单元estimatedItemSize格的高度与单元格的高度不完全相同,则会出现很多错误。我停止设置estimatedItemSize并通过使用原型单元实现了动态单元。这是怎么做的:

创建此协议:

protocol SizeableCollectionViewCell {
    func fittedSize(forConstrainedSize size: CGSize)->CGSize
}

在您的自定义中实现此协议UICollectionViewCell

class YourCustomCollectionViewCell: UICollectionViewCell, SizeableCollectionViewCell {

    @IBOutlet private var mTitle: UILabel!
    @IBOutlet private var mDescription: UILabel!
    @IBOutlet private var mContentView: UIView!
    @IBOutlet private var mTitleTopConstraint: NSLayoutConstraint!
    @IBOutlet private var mDesciptionBottomConstraint: NSLayoutConstraint!

    func fittedSize(forConstrainedSize size: CGSize)->CGSize {

        let fittedSize: CGSize!

        //if height is greatest value, then it's dynamic, so it must be calculated
        if size.height == CGFLoat.greatestFiniteMagnitude {

            var height: CGFloat = 0

            /*now here's where you want to add all the heights up of your views.
              apple provides a method called sizeThatFits(size:), but it's not 
              implemented by default; except for some concrete subclasses such 
              as UILabel, UIButton, etc. search to see if the classes you use implement 
              it. here's how it would be used:
            */
            height += mTitle.sizeThatFits(size).height
            height += mDescription.sizeThatFits(size).height
            height += mCustomView.sizeThatFits(size).height    //you'll have to implement this in your custom view

            //anything that takes up height in the cell has to be included, including top/bottom margin constraints
            height += mTitleTopConstraint.constant
            height += mDescriptionBottomConstraint.constant

            fittedSize = CGSize(width: size.width, height: height)
        }
        //else width is greatest value, if not, you did something wrong
        else {
            //do the same thing that's done for height but with width, remember to include leading/trailing margins in calculations
        }

        return fittedSize
    }
}

现在使您的控制器符合UICollectionViewDelegateFlowLayout,并在其中具有以下字段:

class YourViewController: UIViewController, UICollectionViewDelegateFlowLayout {
    private var mCustomCellPrototype = UINib(nibName: <name of the nib file for your custom collectionviewcell>, bundle: nil).instantiate(withOwner: nil, options: nil).first as! SizeableCollectionViewCell
}

它将用作原型单元以将数据绑定到该单元,然后确定该数据如何影响您要动态化的维度

最后,UICollectionViewDelegateFlowLayout's collectionView(:layout:sizeForItemAt:)必须实施:

class YourViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {

    private var mDataSource: [CustomModel]

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath)->CGSize {

        //bind the prototype cell with the data that corresponds to this index path
        mCustomCellPrototype.bind(model: mDataSource[indexPath.row])    //this is the same method you would use to reconfigure the cells that you dequeue in collectionView(:cellForItemAt:). i'm calling it bind

        //define the dimension you want constrained
        let width = UIScreen.main.bounds.size.width - 20    //the width you want your cells to be
        let height = CGFloat.greatestFiniteMagnitude    //height has the greatest finite magnitude, so in this code, that means it will be dynamic
        let constrainedSize = CGSize(width: width, height: height)

        //determine the size the cell will be given this data and return it
        return mCustomCellPrototype.fittedSize(forConstrainedSize: constrainedSize)
    }
}

就是这样。collectionView(:layout:sizeForItemAt:)以这种方式返回单元格的大小可以防止我不得不使用estimatedItemSize,并且插入和删除单元格效果很好。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.