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

这是我尝试过的设置:

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

  • 这是将单元格背景设置为红色,将 UITextView 背景设置为蓝色时的样子:
    ios - 具有自动布局的 UICollectionView 自动调整单元格大小-LMLPHP

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

    最佳答案

    为 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. 添加对单元子类大小调整的支持

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

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

    我不会详细讨论这个,因为有一个关于为单元配置约束的精彩 SO post。请注意 Xcode 6 broke 与 iOS 7 相关的一堆东西,因此,如果您支持 iOS 7,则需要执行诸如确保在单元格的 contentView 上设置 autoresizingMask 以及将 contentView 的边界设置为单元格时单元格的边界已加载(即 awakeFromNib )。

    您需要注意的是,您的单元格需要比表 View 单元格受到更严格的约束。例如,如果您希望您的宽度是动态的,那么您的单元格需要一个高度约束。同样,如果您希望高度是动态的,那么您将需要对单元格进行宽度约束。

    在您的自定义单元格中实现 preferredLayoutAttributesFittingAttributes
    调用此函数时,您的 View 已经配置了内容(即 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 赢得了动态调整大小恕我直言。

    注意事项

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

    如果我错过了什么,请告诉我,希望我有所帮助,祝您编码愉快

    关于ios - 具有自动布局的 UICollectionView 自动调整单元格大小,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25895311/

    10-14 20:08
    查看更多