当前位置: 首页 > 知识库问答 >
问题:

具有自动布局的自定尺寸单元

公良天逸
2023-03-14

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

以下是我尝试过的设置:

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

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

共有3个答案

於乐语
2023-03-14

对Daniel Galasko的答案进行了一些关键的修改,解决了我所有的问题。不幸的是,我还没有足够的声誉来直接发表评论。

在步骤1中,当使用自动布局时,只需向单元格添加单个父UIView。单元格内的所有内容必须是父级的子视图。这回答了我所有的问题。虽然Xcode会自动为UITableViewCells添加此项,但它不会(但应该)为UICollettionViewCells添加此项。根据医生的说法:

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

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

艾子石
2023-03-14

在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
    }
}
宇文迪
2023-03-14

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

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

systemLayoutSizeFittingSize重命名为systemLayoutSizeFitting

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

TL; DR

查看我的GitHub项目

自定尺寸单元格仅支持flow layout,因此请确保您使用的是自定尺寸单元格。

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

#1.设置估计Itemsize上的UICollettionViewFlowLayout

一旦您设置了estimatedItemSize属性,流程布局将变得动态。

self.flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize

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

这有两种风格;自动布局或自定义重写preferredLayoutAtinitesFittingAtinites

我不会详细讨论这个问题,因为有一篇关于配置单元格约束的精彩文章。请注意,Xcode 6破坏了iOS 7的一系列功能,因此,如果您支持iOS 7,则需要确保在单元格的contentView上设置autoresizingMask,并且在加载单元格时将contentView的边界设置为单元格的边界(即awakeFromNib)。

您需要注意的是,您的单元格需要比表视图单元格受到更严重的约束。例如,如果希望宽度是动态的,则单元格需要高度约束。同样,如果希望高度是动态的,则需要对单元格设置宽度约束。

调用此函数时,您的视图已经配置了内容(即调用了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上,如果不小心,行为会发生一些变化,可能会导致实现崩溃(请参阅此处的更多信息)。当您实现首选布局属性fittingattributes时,您需要确保只更改布局属性的框架一次。如果不这样做,布局将无限期地调用您的实现,并最终崩溃。一种解决方案是在单元格中缓存计算出的大小,并在重复使用单元格或更改其内容时使其无效,就像我使用isheightcomputed属性所做的那样。

在这一点上,你应该有'运作'动态单元格在你的收藏视图。在我的测试中,我还没有找到足够的开箱即用的解决方案,所以如果你有,请随时发表评论。感觉仍然像UITableView赢得了动态大小的战斗。

##注意事项非常注意,如果你使用原型单元格来计算估计的Itemsize-如果你的XIB使用size类,这将被打破。这样做的原因是,当您从XIB加载单元格时,它的大小类将配置为未定义的。这只会在iOS8及以上打破,因为在iOS7大小类将加载基于设备(iPad=常规-任何,iPhone=紧凑型-任何)。您可以设置估计的Itemsize而不加载XIB,或者您可以从XIB加载单元格,将其添加到集合视图(这将设置traitCollection),执行布局,然后将其从超级视图中删除。或者,您也可以让您的单元格覆盖traitCollectiongetter并返回相应的特征。这取决于你。

如果我错过了什么,请告诉我,希望我能帮助你,祝你好运

 类似资料:
  • 我知道如何在UITableView中制作UITableViewCell自身大小。问题是如何只制作特定的单元格自身大小。我的表中有四个不同的自定义UITableView单元格,我想只制作一个单元格自身大小。

  • 我试图用swXXXdp布局文件为不同的屏幕大小创建不同的布局。不幸的是,我仍然不能分开5,0“和6,3”作为可见的附上的图像。两种大小仍然使用相同的文件:layout-sw412dp。对此有什么想法吗?

  • 对于我的表视图单元格的动态高度,我从此链接中引用。在 UITableView 中使用自动布局进行动态单元格布局 这是我的表视图数据源和委托方法的代码 我有 2 个问题: > 我的问题是我在线路附近收到错误 在和。 为什么我必须在单元格中同时写入标签文本“和? 另外,我是否缺少实现单元动态高度所需的任何内容?

  • 我有一个典型的主细节应用程序,它允许用户浏览对象的滚动列表,然后通过推送序列钻取任何特定对象的细节。滚动主列表是使用原型单元构建的UITableView,详细场景是具有固定数量的部分和单元的静态UITableView。 我想在我的应用程序中实现动态类型和自动调整单元格大小,以便用户可以更改基本字体大小。到目前为止,我已经成功地使用原型单元格的滚动列表制作了自定大小的单元格:使用Auto Layou

  • 我正在用Swift设计iOS应用程序,而不是使用自动布局。我没有使用自动布局,因为如果使用自动布局,当标签更新时,设计会重置。目前,我正在设计一款4.7英寸的iPhone,但当我在任何其他尺寸的设备的模拟器上运行它时,设计完全是一团糟。 更新: 我用适当的约束设计了我的故事板。我在override func ViewDidLayoutSubView中添加了UIImages,并将其放置在屏幕之外。当

  • 我应该添加哪些约束来设置宽度和高度与Superview成比例(在我的例子中是UIViewController的视图)在iOS自动布局中,通过自动调整大小,我们可以像下面显示的图片一样进行操作。