如何在ViewController加载时调整UITableViewCell内嵌UICollectionView的布局?
问题描述
在iPad应用中,UITableViewCell内嵌了一个动态高度的UICollectionView。首次加载tableView时,collectionView的单元格布局显示异常;但旋转屏幕改变方向后,布局会自动调整为正常状态。
启动时的异常布局:
旋转后期望在启动时也实现的正确布局:

相关代码
主ViewController中tableView的cellForRowAt方法
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell", for: indexPath) as! CustomTableViewCell cell.layoutIfNeeded() // 屏幕方向变化时失效布局 if let layout = cell.collectionView.collectionViewLayout as? UICollectionViewFlowLayout { layout.invalidateLayout() } cell.heighCollectionView.constant = cell.collectionView.collectionViewLayout.collectionViewContentSize.height return cell }
屏幕方向变化时重载tableView的代码
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) DispatchQueue.main.async { self.tableView.reloadData() } }
CollectionView单元格布局计算代码
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { if traitCollection.horizontalSizeClass == .compact { let width = self.collectionView.frame.size.width let height = width / 2 return CGSize(width: width, height: height) } else { let width = (self.collectionView.frame.size.width - 10) / 2 let height = width / 2 return CGSize(width: width, height: height) } }
CustomTableViewCell子类的awakeFromNib方法
override func awakeFromNib() { super.awakeFromNib() // 初始化代码 collectionView.delegate = self collectionView.dataSource = self }
解决方案
1. 修正CollectionView单元格尺寸计算逻辑
首次加载时self.collectionView.frame尚未正确更新,导致单元格宽度计算错误。改用传入的collectionView参数的边界尺寸来计算:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { let collectionWidth = collectionView.bounds.width if traitCollection.horizontalSizeClass == .compact { let height = collectionWidth / 2 return CGSize(width: collectionWidth, height: height) } else { let width = (collectionWidth - 10) / 2 let height = width / 2 return CGSize(width: width, height: height) } }
2. 调整TableViewCell高度计算时机
在cellForRowAt中先刷新CollectionView数据,等待布局完成后再更新高度约束,同时通知TableView更新行高:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "CustomTableViewCell", for: indexPath) as! CustomTableViewCell // 先刷新CollectionView数据 cell.collectionView.reloadData() // 异步等待布局完成后更新高度约束 DispatchQueue.main.async { let layout = cell.collectionView.collectionViewLayout as! UICollectionViewFlowLayout layout.invalidateLayout() cell.collectionView.layoutIfNeeded() let contentHeight = layout.collectionViewContentSize.height if cell.heighCollectionView.constant != contentHeight { cell.heighCollectionView.constant = contentHeight // 通知TableView更新当前行高 tableView.beginUpdates() tableView.endUpdates() } } return cell }
3. 在ViewController布局稳定后刷新TableView
在viewDidLayoutSubviews中,首次布局完成后刷新TableView,确保所有控件的frame都已正确设置:
override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() static var didInitialLayout = false if !didInitialLayout { didInitialLayout = true tableView.reloadData() } }
4. 优化CustomTableViewCell的布局更新逻辑
在Cell类中添加专门的方法来处理CollectionView高度更新,提高代码可维护性:
class CustomTableViewCell: UITableViewCell { @IBOutlet weak var collectionView: UICollectionView! @IBOutlet weak var heighCollectionView: NSLayoutConstraint! override func awakeFromNib() { super.awakeFromNib() collectionView.delegate = self collectionView.dataSource = self // 根据实际需求注册CollectionViewCell collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "CollectionCell") } // 封装CollectionView高度更新方法 func updateCollectionViewHeight() { DispatchQueue.main.async { self.collectionView.layoutIfNeeded() let layout = self.collectionView.collectionViewLayout as! UICollectionViewFlowLayout layout.invalidateLayout() self.heighCollectionView.constant = layout.collectionViewContentSize.height } } }
内容的提问来源于stack exchange,提问作者Mel
相关产品推荐
相关产品推荐

