【问题标题】:iOS/Swift: Dynamic UITableViewCell row height with embedded UITableView not workingiOS/Swift:嵌入 UITableView 的动态 UITableViewCell 行高不起作用
【发布时间】:2017-06-30 05:15:24
【问题描述】:

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

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

我没有限制封闭的UITableView 的高度,所以我不确定它为什么不起作用。

这是尝试制作动态大小的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 导致了这个问题,但是当这个约束被移除时,整个视图就会崩溃。

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

【问题讨论】:

    标签: ios swift uitableview autolayout constraints


    【解决方案1】:

    虽然这似乎是一个好主意,但将UITableViewAutomaticDimension 与estimatedRowHeight 结合使用在表格视图单元格内有一般内容 的场景中并不好。利用heightForRowAt 方法,您可以在表格居中之前计算每个单元格的大小。

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

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

    这个数组将为我们提供外部表格视图中的部分数量:

    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 方法内部,我们将一个原型单元出列,该原型单元将不会在​​结果视图中使用(因为在这种情况下,dequeueReusableCell 不会在cellForRowAt 内部调用)。我们使用这个原型单元格来提取关于单元格内容的常量和动态的信息。 baseHeight 是单元格所有常量元素的累积高度(加上单元格之间的间距),dynamicHeight 是内部UITableViewCell 的高度。然后每个单元格的高度变为baseHeight + dynamicHeight * cellListFromData[indexPath.section]。

    接下来,我们将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 设置为与我们用来获取单元格高度相同的cellListFromData。此外,在设置单元格数量之后在内部表格视图上调用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
        }
    }
    

    这里不包括与配置内部集合视图相关的方法,因为它与问题无关。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-04-02
      • 2019-04-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多