ios - iOS - 如何使 UICollectionViewCell 根据其内容调整其高度?(包含一个 UITableView)
问题描述
我不知道为什么设计可以适应其内容的单元格如此复杂。它不应该需要那么多代码,我仍然不明白为什么UIKit
不能正确处理这个。
无论如何,这是我的问题(我已经编辑了整篇文章):
我有一个UICollectionViewCell
包含一个UITableView
.
这是我的sizeForItem
方法:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
var cellWidth: CGFloat = collectionView.bounds.size.width
var cellHeight: CGFloat = 0
let cellConfigurator = items[indexPath.item].cellConfigurator
if type(of: cellConfigurator).reuseId == "MoonCollectionViewCell" {
if let cell = collectionView.dequeueReusableCell(withReuseIdentifier: type(of: cellConfigurator).reuseId, for: indexPath) as? MoonCollectionViewCell {
cell.contentView.layoutIfNeeded()
let size = cell.selfSizedTableView.intrinsicContentSize
cellHeight = size.height
}
}
return CGSize.init(width: cellWidth, height: cellHeight)
}
sizeForItem
之前被调用过cellForItem
,这就是 的原因layoutIfNeeded
,因为我无法得到正确的intrinsic content size
。
我已按照建议删除了 XIB,并在 Storyboard 中设计了我的 UICollectionViewCell。
这是我在 Storyboard 中设计的 UICollectionViewCell(只有 UITableViewCell 是在 XIB 文件中设计的)
我只在 UICollectionViewCell 中添加了一个 UITableView。
我希望UICollectionViewCell
根据tableView
.
现在这是我的tableView
:
我创建了一个子类UITableView
(来自这篇文章)
class SelfSizedTableView: UITableView {
var maxHeight: CGFloat = UIScreen.main.bounds.size.height
override func reloadData() {
super.reloadData()
self.invalidateIntrinsicContentSize()
self.layoutIfNeeded()
}
override var intrinsicContentSize: CGSize {
let height = min(contentSize.height, maxHeight)
return CGSize(width: contentSize.width, height: height)
}
}
请注意,我有disabled scrolling
,我有dynamic prototype
tableView 单元格,样式是grouped
.
编辑:检查配置方法,它来自我用来以通用方式配置的协议UICollectionViewCell
func configure(data: [MoonImages]) {
selfSizedTableView.register(UINib.init(nibName: "MoonTableViewCell", bundle: nil), forCellReuseIdentifier: "MoonTableViewCell")
selfSizedTableView.delegate = self
selfSizedTableView.dataSource = moonDataSource
var frame = CGRect.zero
frame.size.height = .leastNormalMagnitude
selfSizedTableView.tableHeaderView = UIView(frame: frame)
selfSizedTableView.tableFooterView = UIView(frame: frame)
selfSizedTableView.maxHeight = 240.0
selfSizedTableView.estimatedRowHeight = 40.0
selfSizedTableView.rowHeight = UITableView.automaticDimension
moonDataSource.data.addAndNotify(observer: self) { [weak self] in
self?.selfSizedTableView.reloadData()
}
moonDataSource.data.value = data
}
仅供参考 ,dataSource 是一个自定义数据源,具有动态值(泛型)和观察者模式,用于在设置数据时重新加载集合/tableView。
当我启动应用程序时,我也有这个警告。
[CollectionView] 在计算布局(即重入调用)的过程中检测到尝试更新布局信息。这将导致意外行为或崩溃。如果在调用委托时触发了布局传递,则可能会发生这种情况。
关于我应该如何处理这个问题的任何提示或建议?
因为我面临一个奇怪的行为,就像我的 sizeForItem 使用随机值一样。UICollectionViewCell
高度与我的内在UITableView
内容大小高度不同。
如果我的 2 行中有 2 行UITableView
,UICollectionView
则在这个大小下并不总是相等。我真的不知道如何实现这一目标......
我应该invalideLayout
吗?
解决方案
也许这不是您想要的答案,但这是我的两分钱。对于您的特定要求,更好的解决方案是远离UITableView
, 并使用UIStackView
您的自定义容器视图。
原因如下:
UITableView
是 的子类UIScrollView
,但由于您已禁用其滚动功能,因此不需要UIScrollView
.UITableView
主要用于重用单元格,以提高性能并使代码更有条理。但是由于您将其设置为与其内容大小一样大,因此您的任何单元格都不会被重用,因此UITableView
不会利用 of 的任何功能。
因此,实际上您不需要也不应该使用其中的任何一个UITableView
或UIScrollView
内部来UICollectionViewCell
满足您的要求。
如果您同意上述部分,以下是我们实践中的一些经验教训:
- 我们总是将大部分底层视图和代码逻辑(主要是数据组装)移动到
UIView
基于自定义视图中,而不是直接放入UITableViewCell
或放入UICollectionViewCell
。然后将其添加到UITableViewCell
orUICollectionViewCell
并contentView
设置约束。通过这种结构,我们可以在更多的场景中复用我们的自定义视图。 - 对于与您类似的要求,我们将创建一个工厂类来创建“行”,类似于您为您创建“单元格”的方式
UITableView
,将它们添加到一个垂直UIStackView
,创建约束决定UIStackView
的宽度。自动布局将处理其余的事情。 - 在你的使用中
UICollectionViewCell
,计算想要的高度,在preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes)
你的单元格的内部,你可以contentView.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel)
用来计算高度,做一些检查并返回。UICollectionView
另外,请记住在更改宽度时使布局无效。
推荐阅读
- android - 无法为“-i ...”找到合适的输出格式
- html - 修改浏览器根调色板
- python - 如何检查 Python 队列中是否存在 obj
- ios - 使不可见的视图控制器的布局无效
- javascript - 检测到依赖循环导入/无循环
- android - 带有 fab 的底部导航
- javascript - babel webpack 导入导出关键字不起作用
- python - 在 Pandas 数据框中应用函数的问题
- javascript - 在数组和多个文本输入之间在 vue.js 中创建双向绑定
- php - Wordpress 永久链接显示“您应该立即更新您的 web.config。” 在老爹