【问题标题】:UICollectionView Self Sizing Cells with Auto LayoutUICollectionView 具有自动布局的自定尺寸单元格
【发布时间】:2014-11-11 18:28:14
【问题描述】:

我正在尝试使用自动布局调整 UICollectionViewCells 的大小,但我似乎无法让单元格根据内容调整大小。我无法理解如何根据单元格的 contentView 中的内容更新单元格的大小。

这是我尝试过的设置:

  • 自定义 UICollectionViewCell,在其 contentView 中带有 UITextView
  • UITextView 的滚动功能已禁用。
  • contentView 的水平约束为:“H:|[_textView(320)]”,即UITextView 固定在单元格的左侧,显式宽度为 320。
  • contentView 的垂直约束为:“V:|-0-[_textView]”,即固定在单元格顶部的UITextView
  • UITextView 的高度约束设置为常数,UITextView 报告将适合文本。

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

我把我一直在玩的项目放在了 GitHub here

【问题讨论】:

  • 你在实现 sizeForItemAtIndexPath 方法吗?
  • @DanielGalasko 我不是。我的理解是,iOS 8 中新的自调整单元格功能不再需要您这样做了。
  • 不确定你从哪里得到这些信息,但你仍然需要,看看 WWDC 摘录asciiwwdc.com/2014/sessions/226
  • 但这又取决于你的用例,确保你实现了estimatedItemSize
  • 2019 - 有必要去看看这个:stackoverflow.com/a/58108897/294884

标签: ios uicollectionview autolayout uicollectionviewcell


【解决方案1】:

这个答案在 iOS 14 中已经过时,增加了组合布局。请考虑更新new API

为 Swift 5 更新

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


为 Swift 4 更新

systemLayoutSizeFittingSize重命名为systemLayoutSizeFitting


为 iOS 9 更新

在看到我的 GitHub 解决方案在 iOS 9 下崩溃后,我终于有时间全面调查这个问题。我现在已经更新了 repo,以包含几个不同配置的示例,用于自定尺寸单元格。我的结论是,自定尺寸单元在理论上很好,但在实践中却很混乱。进行自我调整大小的单元格时请注意。

TL;DR

查看我的GitHub project


仅流式布局支持自行调整单元格大小,因此请确保这是您使用的内容。

您需要设置两件事才能使自定尺寸单元工作。

#1。将estimatedItemSize 设置为UICollectionViewFlowLayout

一旦你设置了estimatedItemSize 属性,流布局就会变成动态的。

self.flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize

#2。添加对单元子类大小的支持

这有两种口味;自动布局自定义覆盖preferredLayoutAttributesFittingAttributes

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

我不会对此进行详细介绍,因为有一个很棒的 SO post 关于为单元格配置约束。请注意Xcode 6 broke 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 上,行为发生了一些变化,如果您不小心,可能会导致您的实现崩溃(查看更多 here)。当您实现preferredLayoutAttributesFittingAttributes 时,您需要确保您只更改一次布局属性的框架。如果您不这样做,布局将无限期地调用您的实现并最终崩溃。一种解决方案是在您的单元格中缓存计算的大小,并在您重复使用单元格或更改其内容时使其无效,就像我对 isHeightCalculated 属性所做的那样。

体验您的布局

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

##注意事项 请注意,如果您使用原型单元格来计算estimatedItemSize - 如果您的XIB uses size classes.这样做的原因是,当您从 XIB 加载单元时,其大小类将配置为 Undefined。这只会在 iOS 8 及更高版本上被打破,因为在 iOS 7 上,将根据设备(iPad = Regular-Any,iPhone = Compact-Any)加载尺寸类。您可以设置estimatedItemSize 而不加载XIB,或者您可以从XIB 加载单元格,将其添加到collectionView(这将设置traitCollection),执行布局,然后将其从superview 中删除。或者,您也可以让您的单元格覆盖 traitCollection getter 并返回适当的特征。这取决于你。

如果我遗漏了什么,请告诉我,希望我能帮上忙,祝你编程好运


【讨论】:

  • 我正在尝试使用流布局实现相同的功能,但是当我以更新后的大小返回 newFrame 时,布局似乎不会重新计算 y 位置,这些位置仍然基于估计大小。缺少什么?
  • 啊,发现了不同之处,你设置的估计高度相当高(400),而我做的是最小值(44)。这有帮助。但是 contentSize 似乎仍然没有正确设置,直到你一直滚动,所以仍然不是很可用。顺便说一句,我将 UITextView 更改为 UILabel,同样的行为。
  • 这似乎在 iOS 9 GM 上被彻底破坏了。设置estimatedItemSize 会导致崩溃——自动布局如何尝试处理 UICollectionViewCell 似乎存在一些巨大的错误。
  • 遇到了类似的问题,有没有人找到解决办法?
  • 其他人所说的您的解决方案并不总是有效。在为 ex 选择和取消选择后尝试更改单元格的约束。整个收藏再次中断。自动调整大小在 ios9 上被破坏了!我将恢复使用 itemSize 委托并自己进行计算。
【解决方案2】:

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

【讨论】:

  • 你在哪里设置这个?在视图中加载?您如何掌握流程布局?
  • 我设法实现了这一点 - 但它有一个奇怪的行为,如果有一个单元格,它会使单元格居中。这是关于它的堆栈溢出问题 - 让我很难过:stackoverflow.com/questions/43266924/…
  • 您可以通过 collectionViews collectionViewLayout 访问流布局,并检查它是否属于 UICollectionViewFlowLayout 类型
  • 它使我的细胞非常小,无用
【解决方案3】:

Daniel Galasko's answer 的一些关键更改解决了我的所有问题。不幸的是,我没有足够的声誉直接发表评论(还)。

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

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

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

【讨论】:

  • 有趣;这是专门针对 Xibs 的,不过还是谢谢你,我会试着和 Github 项目混在一起,看看我能不能重现。也许将答案分为 Xib 与程序化
  • 非常有帮助。谢谢!
  • iOS 9,Xcode 7。单元格在情节提要中进行原型设计,设置自定义子类。尝试创建一个名为contentView 的属性,Xcode 抱怨它与现有属性冲突。尝试将子视图添加到 self.contentView 并为其设置约束,然后应用程序崩溃。
  • @NicolasMiari 我不知道如何以编程方式执行此操作,我的解决方案实际上只是在 XIB 中添加一个 uiview,所有内容都在其中。您不需要创建属性或任何东西。
  • 我面临与@NicolasMiari 相同的问题。当我在 iOS 9 / Xcode 7 上为情节提要中具有自动布局约束的单元格设置estimatedContentSize 时,应用程序崩溃并出现错误的访问异常并且没有有用的堆栈跟踪
【解决方案4】:

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

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

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

    yourFlowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
    

【讨论】:

  • 我很好奇,将单元格内容包装在 UIView 中如何使自动布局性能更好?我认为它在层次结构更浅的情况下会表现得更好?
  • 我没有提到性能,只提到简单性。仅当您在左右之间以及上下之间都有约束时,自调整单元格才会起作用。当所有视图都包装在一个容器中时,最容易实现这一点。如果该容器是 UIStackView,那么如果它是 UIView 的任何其他后代,则更容易。
  • 你能告诉我如何为 UICollectionViewFlowLayoutAutomaticSize 设置高度常数(比如设置高度 25,宽度会自动改变)。
  • 使用 Swift 4.1,Xcode 告诉我 UICollectionViewFlowLayout.automaticSize 已重命名为 UICollectionViewFlowLayoutAutomaticSize
【解决方案5】:
  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. 请参阅这个很棒的、令人兴奋的教程以获取更多参考: UICollectionView with autosizing cell using autolayout in iOS 9 & 10

【讨论】:

    【解决方案6】:

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

    在为此苦苦挣扎了一段时间后,我注意到如果您不禁用滚动,则调整大小不适用于 UITextView:

    let textView = UITextView()
    textView.scrollEnabled = false
    

    【讨论】:

    • 当我尝试滚动时,集合视图单元格不平滑。你有什么解决办法吗?。
    【解决方案7】:

    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 篇关于此的文章中从未在其他任何地方看到过。

    【讨论】:

      【解决方案8】:

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

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

      控制台日志图片:

      第一个首选布局属性FittingAttributes

      (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

      第二个首选布局属性FittingAttributes

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

      第三个首选布局属性FittingAttributes

      (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);
      

      您可以看到collection view 高度从 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;
      

      会导致系统调用无限循环和App崩溃。

      任何尺寸改变,它都会一次又一次地验证所有单元格的preferredLayoutAttributesFittingAttributes,直到每个单元格的位置(即帧)不再改变。

      【讨论】:

        【解决方案9】:

        除了以上答案,

        只需确保将 UICollectionViewFlowLayoutestimatedItemSize 属性设置为某个大小,并且不要实现 sizeForItem:atIndexPath委托方法。

        就是这样。

        【讨论】:

          【解决方案10】:

          如果你实现了 UICollectionViewDelegateFlowLayout 方法:

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

          当你调用collectionview performBatchUpdates:completion:时,大小高度将使用sizeForItemAtIndexPath而不是 preferredLayoutAttributesFittingAttributes

          performBatchUpdates:completion的渲染过程会经过preferredLayoutAttributesFittingAttributes这个方法,但是会忽略你的修改。

          【讨论】:

          • 我见过这种不当行为,但仅在估计大小为零时。您确定要设置估计尺寸吗?
          【解决方案11】:

          对谁有帮助,

          如果设置了estimatedItemSize,我会遇到严重的崩溃。即使我在numberOfItemsInSection 中返回 0。因此,单元格本身和它们的自动布局并不是导致崩溃的原因......即使是空的,collectionView 也会崩溃,只是因为 estimatedItemSize 设置为自调整大小。

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

          去看看。

          【讨论】:

          • 尝试在collectionView.reloadData()之后调用collectionView.collectionViewLayout.invalidateLayout()
          • 对于 ios10 及以下添加此代码 ` override func viewWillLayoutSubviews() { super.viewWillLayoutSubviews() if #available(iOS 11.0, *) { } else { mainCollectionView.collectionViewLayout.invalidateLayout() } }`
          【解决方案12】:

          对于任何尝试一切都没有运气的人来说,这是唯一让它对我有用的东西。 对于单元格内的多行标签,请尝试添加这条神奇的线:

          label.preferredMaxLayoutWidth = 200
          

          更多信息:here

          干杯!

          【讨论】:

            【解决方案13】:

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

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

            flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize

            1. collectionView(:cellForItemAt:)设置containerView.widthAnchor.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。计算并设置 UITextView 的 heightAnchor.constant。

            所以,每当设置 contentView 的宽度时,我们都会在 didSetmaxWidth 中调整 UITextView 的高度。

            UICollectionViewCell 内部:

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

            这些步骤将为您带来想要的结果。

            Complete runnable gist

            参考:Vadim Bulavin 博文 - Collection View Cells Self-Sizing: Step by Step Tutorial

            截图:

            【讨论】:

            • 很棒的答案?
            • @Alex 动态高度的水平滚动集合视图怎么样?
            【解决方案14】:

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

            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
            }
            

            【讨论】:

              【解决方案15】:

              更新更多信息:

              • 如果你使用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会导致不同的section inset设置不起作用。即函数:(UIEdgeInsets)collectionView:layout:insetForSectionAtIndex:.

              【讨论】:

                【解决方案16】:

                我尝试使用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,并且插入和删除单元格效果很好。

                【讨论】:

                  猜你喜欢
                  • 2020-03-29
                  • 2015-08-19
                  • 2017-05-07
                  • 2013-10-26
                  • 2014-09-02
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多