iOS/swift : Dynamic UITableViewCell row height with embedded UITableView not working

标签 ios swift uitableview autolayout constraints

我有一个 UITableViewCell,其中包含顶部的 UICollectionView 和底部的 UITableView。这个想法是,将在内部 UITableView 中创建动态数量的单元格,并且包含两个 subview 的父 UITableViewCell 将按比例增加其高度。

我正在尝试利用 UITableViewCellestimatedRowHeight + UITableViewAutomaticDimention 功能,该功能将允许单元格高度动态增加。但是,它不起作用。它从 View 中完全删除了嵌入的 UITableView

Comparison of implementations

我没有做出任何限制所包含的 UITableView 高度的约束,所以我不确定为什么它不起作用。

Contraints

下面是尝试动态调整大小的 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
    }
}

我唯一的猜测是约束 bottom = Inner Table View.bottom + 7 导致了这个问题,但是当这个约束被删除时,整个 View 就会崩溃。

如何才能使复杂的外部 UITableViewCell 根据嵌入 UITableView 中的单元格数量动态调整高度?

最佳答案

虽然这看起来是个好主意,但将 UITableViewAutomaticDimensionestimatedRowHeight 结合使用并不适合在这样的场景中使用,在这种情况下,我们有通用的 TableView 单元格内的内容。利用 heightForRowAt 方法,您可以在将表格居中之前计算每个单元格的大小。

一旦我们知道内部表格中有多少个单元格,您就需要创建一个数组,其元素对应于内部单元格的数量,最终确定外部单元格的高度,因为所有其他内容都是恒定的。

let cellListFromData: [CGFloat] = [3, 1, 4]

这个数组将为我们提供外部 TableView 中的部分数量:

func numberOfSections(in tableView: UITableView) -> Int {
    return cellListFromData.count
}

我们将通过以下方式将此数组中的每个元素转换为单元格高度:

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])
}

也就是说,在 heightForRowAt 方法内部,我们将不会在结果 View 中使用的原型(prototype)单元出队(因为 dequeueReusableCell 未在 内部调用)在本例中为 cellForRowAt)。我们使用此原型(prototype)单元来提取有关单元内容的恒定动态信息。 baseHeight 是单元格所有常量元素的累积高度(加上单元格之间的间距),dynamicHeight 是内部 UITableViewCell< 的高度。每个单元格的高度将变为 baseHeight +dynamicHeight * cellListFromData[indexPath.section]

接下来,我们将 numberOfCells 变量添加到自定义单元格的类中,并在主 TableView 中的 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 的设置与我们用于获取单元格高度的 cellListFromData 相同。此外,在设置单元格数量后,在内部表格 View 上调用 reloadData() 至关重要,以便我们在 UI 中看到更新。

完整代码如下:

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
    }
}

此处不包含与配置内部 Collection View 相关的方法,因为它与问题无关。

关于iOS/swift : Dynamic UITableViewCell row height with embedded UITableView not working,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44839030/

相关文章:

ios - 是否可以在 UITableViewCell 中包含一个 UITableView?

swift - 从 CoreData 中删除字符串

ios - 动画宽度约束时 UITextField 文本跳转

ios - 未应用 UITextView 属性颜色 - iOS

swift - 在 Swift 中编写自定义访问器方法

ios - Swift 中的多维对象数组错误?

ios - firebase childByAutoId.key 是可选的

ios - 自定义表格单元格未调整大小以适合内容 View

ios - 无法在 UIViewController 中为 UIBarButtonItem 创建 IBOutlet

javascript - 使用 nsstring 编码