Swift iOS动态调整UITableView高度出现布局延迟问题
问题根源
布局延迟的核心原因是你把表格高度调整逻辑放在了viewDidAppear中,这个方法的执行时机是页面已经完全渲染、展示到用户屏幕上之后,用户必然会先看到Storyboard中默认300高度的错误布局,等代码执行完才会看到控件移位到正确位置。
另外你直接读取ingredientTable.contentSize.height的时机也不对,表格没有完成内部cell布局的时候,这个值不是真实的内容高度。
实现方案
把高度调整逻辑提前到视图展示给用户之前的布局节点,主动触发布局计算保证拿到准确高度,用户看到的第一帧就是正确布局,完全不会有跳位延迟。
- 第一步:删除你当前写在
viewDidAppear里的所有高度调整代码,不要在页面已经显示后再做核心布局修改。 - 第二步:在控制器中添加一个独立的高度更新方法,统一处理高度计算、约束更新、滚动开关逻辑:
private func updateIngredientTableHeight() { // 强制表格完成内部布局,拿到准确的内容高度 ingredientTable.layoutIfNeeded() let contentHeight = ingredientTable.contentSize.height // 高度取内容高度和300阈值的较小值,不需要分支判断 tableIngredientHeight.constant = min(contentHeight, 300) // 内容高度超过300才开启表格滚动,否则关闭滚动优化体验 ingredientTable.isScrollEnabled = contentHeight >= 300 // 主动触发当前视图约束更新,不等待系统下一个布局周期 self.view.layoutIfNeeded() }
- 第三步:在
viewDidLoad方法的末尾,主动触发表格第一次数据刷新,保证数据提前加载完成:
// 把这行加在viewDidLoad方法的最后 ingredientTable.reloadData()
- 第四步:重写
viewDidLayoutSubviews生命周期方法,在视图完成子控件布局、还未展示给用户的时候更新表格高度,注意必须调用父类实现:
override func viewDidLayoutSubviews() { super.viewDidLayoutSubviews() updateIngredientTableHeight() }
扩展说明
如果之后你需要实现食材增删改的动态更新逻辑,只需要在调用ingredientTable.reloadData()之后立刻调用updateIngredientTableHeight(),高度就会实时更新,不会出现布局跳变。
Storyboard中设置的300默认高度作为占位值即可,不需要修改,因为我们在视图展示给用户之前就会把约束更新为正确值,用户完全看不到占位状态。
不要用KVO监听表格contentSize变化来更新高度,这种方式容易触发循环布局,产生不必要的性能损耗,上述方案已经可以覆盖所有静态、动态内容的场景。
内容的提问来源于stack exchange,提问作者Tori Mori
相关产品推荐
相关产品推荐

