iOS 13/10.3下绘制前基于UITableView高度设置Cell高度的难题
解决iOS中UIPageViewController子视图UITableView高度延迟获取的问题
这个场景我之前做分页类页面时也踩过坑,先给你梳理几个可行的思路,不一定非要切换到UICollectionView哈:
1. 先搞懂布局延迟的本质
UIPageViewController的子VC布局时机确实特殊:因为页面切换有过渡动画,子VC的view可能要等动画完成后才真正被添加到window层级,这就导致didMoveToWindow()会在viewDidAppear()之后触发,甚至后续还会有几次layoutSubviews()调用——这都是动画和布局调整的正常流程。
2. 用"布局稳定判断"替代单次钩子调用
你试过的生命周期方法都是对的,但问题是不能在第一次触发时就处理,得等视图高度稳定下来。可以通过记录上一次的高度,只有当高度变化小于阈值(比如1pt,排除布局过程中的微小波动)时,再执行cell高度计算:
private var lastTableViewHeight: CGFloat = 0 override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() let currentHeight = tableView.bounds.height // 高度变化极小,认为布局已稳定 if abs(currentHeight - lastTableViewHeight) < 1 { // 计算能容纳的整数cell数量(这里假设你有预估的cell基础高度) let baseCellHeight: CGFloat = 80 let maxVisibleCells = Int(currentHeight / baseCellHeight) let finalCellHeight = currentHeight / CGFloat(maxVisibleCells) // 设置高度并刷新,注意只执行一次避免重复刷新 tableView.rowHeight = finalCellHeight tableView.reloadData() lastTableViewHeight = 0 // 重置标记,防止后续误触发 } else { lastTableViewHeight = currentHeight } }
3. 结合UIPageViewController的代理时机
利用pageVC的动画完成回调,在页面真正稳定显示后再触发计算,能避免预加载的子VC提前执行逻辑:
// 在你的UIPageViewController代理中 extension YourPageVC: UIPageViewControllerDelegate { func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { // 动画完成且页面切换成功时,拿到当前显示的子VC guard completed, let currentChildVC = pageViewController.viewControllers?.first as? YourChildVC else { return } currentChildVC.updateTableViewCellHeight() } } // 在子VC中实现方法 func updateTableViewCellHeight() { // 强制触发一次布局 tableView.layoutIfNeeded() let tableViewHeight = tableView.bounds.height let baseCellHeight: CGFloat = 80 let cellCount = Int(tableViewHeight / baseCellHeight) tableView.rowHeight = tableViewHeight / CGFloat(cellCount) tableView.reloadData() }
4. 提前从父视图约束反推高度
如果你的UITableView是通过约束和父视图绑定的(比如上下左右对齐),其实可以不用等tableView布局完成,直接从父视图的最终高度反推:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) view.layoutIfNeeded() // 父视图高度确定后,减去tableView的内边距等就是tableView的高度 let parentHeight = view.bounds.height let tableViewHeight = parentHeight - tableView.contentInset.top - tableView.contentInset.bottom // 后续cell高度计算逻辑同上 }
关于是否切换到UICollectionView
如果你的需求只是让容器刚好显示整数个"单元格",UICollectionView确实更灵活——可以自定义布局直接将itemSize设为collectionView高度 / cell数量,布局初始化时就能确定尺寸,不会有延迟问题。但如果只是这个单一需求,上面的方法完全能解决,没必要重构现有代码。
内容的提问来源于stack exchange,提问作者Rick
相关产品推荐
相关产品推荐

