首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >具有自动布局功能的UICollectionView自动调整单元大小

具有自动布局功能的UICollectionView自动调整单元大小
EN

Stack Overflow用户
提问于 2014-09-17 16:02:16
回答 17查看 281.7K关注 0票数 226

我试图让自调整大小的UICollectionViewCells与自动布局一起工作,但我似乎无法让单元格根据内容调整自己的大小。我很难理解单元格的大小是如何根据单元格的contentView中的内容更新的。

下面是我尝试过的设置:

contentView.

  • Scrolling中包含UITextViewUITextView自定义UICollectionViewCell被禁用。

  • contentView的水平约束为:"H:|_textView(320)",即UITextView固定在单元格左侧,显式宽度为320。

  • contentView的垂直约束为:"V:|-0-_textView",即固定在单元格顶部的UITextView

  • UITextView的高度约束设置为一个常量,UITextView报告将适合该常量。

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

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

EN

回答 17

Stack Overflow用户

回答已采纳

发布于 2014-09-17 17:04:24

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

针对Swift 5更新

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

针对Swift 4更新

systemLayoutSizeFittingSize已重命名为systemLayoutSizeFitting

针对iOS 9进行了更新

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

TL;DR

查看我的GitHub project

只有流式布局才支持自调整单元格大小,因此请确保您使用的是自调整大小的单元格。

要使自调整大小的单元格正常工作,需要进行两项设置。

#1.在UICollectionViewFlowLayout上设置estimatedItemSize

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

代码语言:javascript
运行
AI代码解释
复制
self.flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize

#2.添加对计算单元格子类大小的支持

这有两种风格:自动布局preferredLayoutAttributesFittingAttributes自定义覆盖。

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

我不会在中详细介绍这一点,因为有一个关于为单元配置约束的出色的SO post。只需注意在iOS 7中Xcode 6 broke一大堆东西,所以,如果你支持iOS 7,你将需要做一些事情,比如确保autoresizingMask设置在单元格的contentView上,以及确保contentView的边界在加载单元格时设置为单元格的边界(即awakeFromNib)。

您需要注意的是,您的单元格需要比表视图单元格更严格的约束。例如,如果您希望宽度是动态的,那么您的单元格就需要高度约束。同样,如果您希望高度是动态的,那么您需要对单元格进行宽度约束。

在自定义单元中实现preferredLayoutAttributesFittingAttributes

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

代码语言:javascript
运行
AI代码解释
复制
//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赢得了动态大小之战。

##Caveats请注意,如果您使用原型单元来计算estimatedItemSize -如果您的XIB uses size classes将中断。这样做的原因是,当您从XIB加载单元时,它的size类将配置为Undefined。这只会在iOS 8和更高版本上被破坏,因为在iOS 7上,size类将基于设备加载(iPad = Regular-Any,iPhone = Compact-Any)。您可以在不加载XIB的情况下设置estimatedItemSize,也可以从XIB加载单元,将其添加到collectionView (这将设置traitCollection),执行布局,然后将其从superview中删除。或者,您也可以让您的单元覆盖traitCollection获取方法并返回适当的特征。由你决定。

如果我遗漏了什么,请让我知道,希望我能帮上忙,祝你编码好运

票数 339
EN

Stack Overflow用户

发布于 2017-03-22 10:26:43

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

代码语言:javascript
运行
AI代码解释
复制
self.flowLayout.estimatedItemSize = CGSize(width: 100, height: 100)

您可以使用以下命令:

代码语言:javascript
运行
AI代码解释
复制
self.flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize

它具有更好的性能,特别是当集合视图中的单元格具有恒定宽度时。

访问流程布局:

代码语言:javascript
运行
AI代码解释
复制
override func viewDidLoad() {
   super.viewDidLoad()

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

Swift 5更新:

代码语言:javascript
运行
AI代码解释
复制
override func viewDidLoad() {
   super.viewDidLoad()

   if let flowLayout = collectionView?.collectionViewLayout as? UICollectionViewFlowLayout {
      flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
    }
}
票数 62
EN

Stack Overflow用户

发布于 2015-07-07 21:35:26

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

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

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

然后完全跳过步骤3。它不是必需的。

票数 45
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25895311

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档