如何根据屏幕大小调整UITableViewCell的高度,其中包含UICollectionView?

3

我有以下布局

  • UITableView
    • UITableViewCell (类别单元格)
      • 标签
      • 按钮
      • UICollectionView
        • UICollectionViewCell (物品单元格)
          • UIImageView
          • UILabel

我试图使UICollectionView始终显示3个项目,无论屏幕大小如何。我能够根据屏幕宽度显示项目,并设置高度。然而,来自CategoryCell内部的TableView的高度没有改变。以下是代码:

// CategoryCell.swift

func awakeFromNib() {
    super.awakeFromNib()

    // Calculate width and height based on screen width
    let screenWidth = UIScreen.main.bounds.width
    let itemWidth = screenWidth / 3.0
    let itemHeight = itemWidth / 0.75 // 3:4 aspect ratio

    // Change height of table view cell
    self.bounds.size.height = self.bounds.size.height - collectionView.bounds.size.height + itemHeight
    // This is the line does nothing
    // It should remove collectionView height from tableView (height of collectionView is set through autolayout) then add he new height to it.

    // Set collection view height to equal to item height
    collectionView.bounds.size.height = itemHeight

    // set item height
    let layout = collectionViewProducts.collectionViewLayout as! UICollectionViewFlowLayout
    layout.itemSize = CGSize(width: itemWidth, height: itemHeight - 1.0)
    // -1.0 because item/cell height needs to be SMALLER than collection view height
}

如何在单元格类内部更改表格视图单元格高度? 我唯一的猜测是,我不应该在awakeFromNib中执行这些操作,但我找不到另一个函数来调用这些操作。

编辑:我正在使用RxSwift,因此我的数据源代码如下:

let observable = Observable.just(data)
observable.bindTo(tableView.rx.items(cellIdentifier: "CategoryCell", cellType: CategoryCell.self)) { (row, element, cell) in
    cell.setCategory(category: element)
}.disposed(by: disposeBag)

tableView.rx.setDelegate(self).disposed(by: disposeBag)
4个回答

2
您可以实现UITableViewDelegateheightForRowAt方法,并基于一个变量返回一个值。您可以在进行UICollectionView itemHeight计算的任何地方设置该变量。因此,当您完成计算后,应该能够进行表格视图数据重新加载,并使用新的itemHeight值更新布局。
我尚未测试此代码,但上述内容应该可以正常工作。如果您遇到任何问题或者我对您的要求有误,请告诉我。

1

为集合视图提供约束,并在tableviewcell页面中创建collectionviewcell输出口以及collectionviewheight约束输出口。就像在tableviewcell页面中一样:

class HomeServiceTableCell: UITableViewCell {

  @IBOutlet weak var dealsCollectionView: UICollectionView!
  @IBOutlet weak var dealsCollectionHeight: NSLayoutConstraint!
  @IBOutlet weak var dealsImage: UIImageView!

  // like this in the main page cellforRowAt indexPath function

  func tableView (_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = homeServiceTable.dequeueReusableCell ( withIdentifier:  "homeServiceTableCell6" ) as! homeServiceTableCell6
    cell.dealsImage.image = UIImage(named: "deals.png")
    cell.dealsCollectionView.tag = indexPath.row
    cell.dealsCollectionView.delegate = self
    cell.dealsCollectionView.dataSource = self
    cell.dealsCollectionView.reloadData()
    cell.dealsCollectionHeight.constant = cell.dealsCollectionView.collectionViewLayout.collectionViewContentSize.height

    return cell
  }

  func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat  {
    return UITableViewAutomaticDimension
  }

  // lastly add this line in viewWillAppear function

  override func viewWillAppear(_ animated: Bool) {
    self.homeServiceTable.layoutSubviews()
  }
}

0
你需要为每个单元格提供tableview的高度,然后根据此计算出collectionview单元格的高度。要实现tableview动态高度的单元格,你需要实现这些方法。
func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return UITableViewAutomaticDimension
}

或者如果您需要固定高度,那么只需使用这些方法并根据您的计算提供单元格高度即可。

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return fixedSize //e.g 100 
}

试试这个,希望能帮到你。


动态高度对我不起作用。 固定高度会显示我分配的高度的单元格。 但是,tableViewCell不会更新tableView本身。 - Gasim
请问您能否在此处发布您的tableview的数据源和代理代码? - Pankaj K.
我添加了数据源代码。我的委托代码只有你提供的内容。 - Gasim
另外,我认为我找到了一个不同的解决方案。 - Gasim

0
谢谢 @Prince 和 @Fahim。你们的回答让我想到将我的行高逻辑移到 tableView 委托中。由于我是基于屏幕宽度和纵横比计算高度,所以我只需将相同的逻辑移到 tableView 高度中即可。
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    let screenWidth = UIScreen.main.bounds.size.width

    // 3 items + 10px gap between cells
    let itemWidth = (screenWidth / 3.0) - 20

    // 3:4 aspect ratio + other elements
    let itemHeight = (itemWidth) / 0.75 + 110

    return itemHeight
}

目前这个解决方案对我来说正常工作,但我想改变它以考虑单元格本身。

我知道在答案中提问很奇怪,但它与此线程有关,所以我认为在这里提问是最好的。如何从indexPath获取单元格对象?使用tableView.cellForRow(at: indexPath)会导致错误访问。


你可以像这样从TableView中获取Cell:let cell = tableView.cellForRow(at: indexPath) as! yourCellClass。请注意,如果Cell不可见或IndexPath超出范围,它将返回nil。 - Pankaj K.
我一直收到EXC_BAD_ACCES。 - Gasim
你想在哪里访问它?如果单元格尚未创建,则无法访问它。 - Pankaj K.
你可以根据数组中的数据计算大小。我的意思是,你可以使用索引路径来计算大小。 - Pankaj K.
是的,但是保护变量也会导致EXC_BAD_ACCESS错误。我将拥有两个原型单元格,因此我希望每个单元格的类都能计算大小,并且heightForRowAt只需调用该函数即可计算单元格的大小。 - Gasim
请查看以下问题(已将问题移至另一个线程):https://dev59.com/vqDia4cB1Zd3GeqPB1O1#43015572 - Gasim

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接