UITableViewCell内的UICollectionView如何根据屏幕大小调整tableview单元格高度

Posted

技术标签:

【中文标题】UITableViewCell内的UICollectionView如何根据屏幕大小调整tableview单元格高度【英文标题】:UICollectionView inside UITableViewCell how to adjust tableview cell height based on screen size 【发布时间】:2017-03-25 00:45:25 【问题描述】:

我有以下布局

UITableView UITableViewCell(类:CategoryCell) 标签 按钮 UICollectionView UICollectionViewCell(类:ItemCell) UIImageView UILabel

我正在尝试让 UICollectionView 始终显示 3 个项目,无论屏幕大小如何。我能够根据屏幕宽度显示要显示的项目,并且能够设置高度。但是,表格视图的高度不会从 CategoryCell 内部改变。代码如下:

// 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)

【问题讨论】:

【参考方案1】:

您可以实现UITableViewDelegateheightForRowAt 并根据变量返回一个值。无论您在哪里进行UICollectionView itemHeight 计算,都可以设置变量。因此,当您完成计算后,您应该能够重新加载表格视图数据,并且应该使用新的 itemHeight 值更新布局。

我还没有测试过代码,但上面应该可以工作。如果您遇到任何问题,或者我以某种方式误解了您的要求,请告诉我。

【讨论】:

【参考方案2】:

为collection view提供约束,在tableviewcell页面中设置collectionviewcell出口,在同一个tableviewcell页面中设置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()
  

【讨论】:

【参考方案3】:

您需要为每个单元格提供 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 本身。 你能把你的tableview的数据源和委托代码贴在这里 我添加了数据源代码。我的委托代码只有您在上面提供的代码。 另外,我想我找到了不同的解决方案。【参考方案4】:

谢谢@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 获取单元格 let cell = tableView.cellForRow(at: indexPath) as! yourCellClass 请注意,如果单元格不可见或索引路径超出范围,它将返回 nil 我不断收到 EXC_BAD_ACCES。 你想在哪里访问它?如果尚未创建单元格,则无法访问它。 您可以根据数组中的数据计算大小。我的意思是你可以使用索引路径来计算大小。 是的,但是保护变量也会给出 EXC_BAD_ACCESS。我将有两个原型单元格,所以我希望每个单元格的类来计算大小,heightForRowAt 只是调用函数来计算单元格

以上是关于UITableViewCell内的UICollectionView如何根据屏幕大小调整tableview单元格高度的主要内容,如果未能解决你的问题,请参考以下文章

UITableViewCell 内的 UIView 上的 UIGestureRecognizer

UITableViewCell 内的 UIStackView

如何增加 UItableviewcell 内的 UItableview 高度?

捏放大到 UITableViewCell 内的 UIImageView

iOS - UITableViewCell 内的 UIScrollView 内的 UIView 未触发 UITapGestureRecognizer

UITableViewCell 内的 TableView - 必须注册一个 nib 或类