[英]iOS/Swift: Dynamic UITableViewCell row height with embedded UITableView not working
I have a UITableViewCell
which contains a UICollectionView
on top and a UITableView
on the bottom. 我有一个UITableViewCell
,它的顶部包含一个UICollectionView
,底部包含一个UITableView
。 The idea is that a dynamic amount of cells will be created in the inner UITableView
and the parent UITableViewCell
that encloses the two subviews will increase its height proportionally. 这个想法是,将在内部UITableView
创建动态数量的单元格,并且将包围两个子视图的父级UITableViewCell
会按比例增加其高度。
I am trying to take advantage of the estimatedRowHeight
+ UITableViewAutomaticDimention
feature of the UITableViewCell
that will allow the cell height to increase dynamically. 我试图把优势estimatedRowHeight
+ UITableViewAutomaticDimention
的特征UITableViewCell
,使单元格高度动态增加。 However, it is not working. 但是,它不起作用。 It completely removes the embedded UITableView
from view. 它将嵌入式UITableView
从视图中完全删除。
I have not made any constraints that limit the height of the enclosed UITableView
, so I am not sure why it is not working. 我没有做出任何限制封闭UITableView
高度的约束,所以我不确定为什么它不起作用。
Here is the implementation that attempts to make a dynamically sized UITableViewCell
: 这是尝试制作动态大小的UITableViewCell
:
class OverviewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
navigationItem.title = "Enclosed Table View Example"
}
func numberOfSections(in tableView: UITableView) -> Int {
return 3
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
return 325 // Height for inner table view with 1 cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 45
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cell = tableView.dequeueReusableCell(withIdentifier: "appHeaderCell") as! AppHeaderCell
return cell
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "appCell", for: indexPath) as! AppCell
return cell
}
}
My only guess is that the constraint bottom = Inner Table View.bottom + 7
is causing the issue, but the entire view falls apart when this constraint is removed. 我唯一的猜测是,约束bottom = Inner Table View.bottom + 7
引起了问题,但是当删除此约束时,整个视图就会崩溃。
What can I do to make the complex outer UITableViewCell
dynamically adjust height based on the number of cells in the embedded UITableView
? 如何使复杂的外部UITableViewCell
根据嵌入式UITableView
的单元格数量动态调整高度?
Although it may seem like a good idea, the use of UITableViewAutomaticDimension
in conjunction with estimatedRowHeight
is not good to use in scenarios like this where we have general content inside table view cells. 尽管这似乎是一个好主意,但在这样的场景(我们在表格视图单元格中拥有常规内容)的情况下,将UITableViewAutomaticDimension
与estimatedRowHeight
高度结合使用并不是很好。 Making use of the heightForRowAt
method, you can calculate the size of each individual cell before it centers the table. 利用heightForRowAt
方法,您可以计算每个单个单元格在表格居中之前的大小。
Once we know how many cells will be in the inner table, you need to create an array whose elements correspond to the number inner cells that will ultimately determine the height of the outer cell, as all other content is constant. 一旦我们知道内部表中有多少个单元格,就需要创建一个数组,该数组的元素与内部单元格的数量相对应,这将最终确定外部单元格的高度,因为所有其他内容都是恒定的。
let cellListFromData: [CGFloat] = [3, 1, 4]
This array will give us the number of sections in our outer table view: 该数组将为我们提供外部表视图中的节数:
func numberOfSections(in tableView: UITableView) -> Int {
return cellListFromData.count
}
We will convert each element in this array to a cell height in the following way: 我们将通过以下方式将该数组中的每个元素转换为像元高度:
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let prototypeCell = tableView.dequeueReusableCell(withIdentifier: "appCell") as! AppCell
let baseHeight = betweenCellSpacing + prototypeCell.innerCollectionView.contentSize.height + prototypeCell.innerTableView.sectionHeaderHeight + outerTableView.sectionHeaderHeight
let dynamicHeight = prototypeCell.innerTableView.contentSize.height - prototypeCell.innerTableView.sectionHeaderHeight
return baseHeight + (dynamicHeight * cellListFromData[indexPath.section])
}
That is, inside of the heightForRowAt
method, we dequeue a prototype cell that will not be used in the resulting view (as dequeueReusableCell
is not called inside cellForRowAt
in this case). 也就是说,在heightForRowAt
方法内部,我们使将不在结果视图中使用的原型单元出队(因为在这种情况下,在cellForRowAt
内部未调用dequeueReusableCell
)。 We use this prototype cell to extract information about what is constant and what is dynamic about the cell's content. 我们使用此原型单元提取有关单元内容的常量和动态信息。 The baseHeight
is the accumulated height of all the constant elements of the cell (plus the between-cell spacing) and the dynamicHeight
is the height of an inner UITableViewCell
. baseHeight
是单元格中所有常量元素的累积高度(加上单元格之间的间隔),而dynamicHeight
是内部UITableViewCell
的高度。 The height of each cell then becomes baseHeight + dynamicHeight * cellListFromData[indexPath.section]
. 然后,每个单元格的高度变为baseHeight + dynamicHeight * cellListFromData[indexPath.section]
。
Next, we add a numberOfCells
variable to the class for the custom cell and set this in the cellForRowAt
method in the main table view: 接下来,我们向自定义单元格的类中添加一个numberOfCells
变量,并在主表视图的cellForRowAt
方法中进行设置:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "appCell", for: indexPath) as! AppCell
cell.numberOfCells = Int(cellListFromData[indexPath.section])
cell.innerTableView.reloadData()
return cell
}
numberOfCells
is set with the same cellListFromData
that we used to get the height of the cell. 用我们用来获取单元格高度的相同cellListFromData
设置numberOfCells
。 Also, it is critical to call reloadData()
on the inner table view after setting its number of cells so that we see that update in the UI. 同样, 在设置内部单元格视图的单元格数之后 ,在内部表视图上调用reloadData()
至关重要,这样我们才能在UI中看到该更新。
Here is the full code: 这是完整的代码:
class OverviewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
@IBOutlet weak var outerTableView: UITableView!
let cellSpacing: CGFloat = 25
let data: [CGFloat] = [3, 1, 4]
override func viewDidLoad() {
super.viewDidLoad()
}
func numberOfSections(in tableView: UITableView) -> Int {
return data.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 1
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
let prototypeCell = tableView.dequeueReusableCell(withIdentifier: "appCell") as! AppCell
let baseHeight = cellSpacing + prototypeCell.innerCollectionView.contentSize.height + prototypeCell.innerTableView.sectionHeaderHeight + outerTableView.sectionHeaderHeight
let dynamicHeight = prototypeCell.innerTableView.contentSize.height - prototypeCell.innerTableView.sectionHeaderHeight
return baseHeight + (dynamicHeight * data[indexPath.section])
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "appCell", for: indexPath) as! AppCell
cell.numberOfCells = Int(data[indexPath.section])
cell.innerTableView.reloadData()
return cell
}
}
class AppCell: UITableViewCell, UITableViewDataSource, UITableViewDelegate {
@IBOutlet weak var innerCollectionView: UICollectionView!
@IBOutlet weak var innerTableView: UITableView!
var numberOfCells: Int = 0
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return numberOfCells
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let cell = tableView.dequeueReusableCell(withIdentifier: "featureHeaderCell") as! BuildHeaderCell
return cell
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "innerCell", for: indexPath) as! InnerCell
return cell
}
}
Methods relating to configuring the inner collection view is not included here as it is not related to the problem. 与配置内部集合视图有关的方法不在此处,因为它与问题无关。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.