You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Auto Layout实现单个视图中两个UITableView的动态高度调整

解决单个ViewController中两个UITableView的动态高度适配问题

嘿,这个需求我之前做项目时刚好碰到过,要实现「尽量让表格不滚动,总高度超屏时等高」的效果,其实通过动态计算内容高度+约束优先级调整就能搞定,下面一步步来实现:

一、先做好基础约束配置

给两个UITableView设置好基础布局:

  • 给第一个tableView加上顶部约束(比如和导航栏底部对齐)、左右边缘约束;
  • 给第二个tableView加上底部约束(比如和tabBar顶部对齐)、左右边缘约束;
  • 在两个tableView之间添加固定间距的约束;
  • 给每个tableView添加一个高度约束,并把这两个约束的引用保存到代码里(比如叫tableView1HeightConstraint和tableView2HeightConstraint),初始值可以随便设,后面会动态修改。

二、实现内容高度的准确计算

要让tableView的高度适配内容,首先得能算出它的实际内容高度。这里写个工具方法,注意要在tableView刷新数据后调用,确保contentSize是最新的:

private func calculateTableViewContentHeight(_ tableView: UITableView) -> CGFloat {
    // 先强制更新布局,保证contentSize准确
    tableView.layoutIfNeeded()
    // 用sizeThatFits来获取最合适的高度,比直接取contentSize更可靠(尤其是带表头表尾的情况)
    let fittingSize = CGSize(width: tableView.bounds.width, height: UIView.layoutFittingCompressedSize.height)
    return tableView.sizeThatFits(fittingSize).height
}

注意:要确保你的tableView已经开启了自动行高,也就是设置了tableView.rowHeight = UITableView.automaticDimension和tableView.estimatedRowHeight = 80(值随便设个合理的就行),否则contentSize会不准确。

三、动态调整高度逻辑

在合适的时机(比如view加载完成、tableView数据刷新后)调用下面的方法,来判断是让两个tableView各自适配内容,还是强制等高:

private func updateTableViewHeights() {
    // 先算出当前屏幕的可用高度(减去导航栏、tabBar的高度,根据你的实际布局调整)
    let navBarHeight = navigationController?.navigationBar.frame.height ?? 0
    let tabBarHeight = tabBarController?.tabBar.frame.height ?? 0
    let availableScreenHeight = view.bounds.height - navBarHeight - tabBarHeight
    
    // 计算两个tableView的内容高度
    let tableView1ContentHeight = calculateTableViewContentHeight(tableView1)
    let tableView2ContentHeight = calculateTableViewContentHeight(tableView2)
    // 两个tableView的总高度(加上中间的间距)
    let totalContentHeight = tableView1ContentHeight + tableView2ContentHeight + tableViewSpacingConstraint.constant
    
    if totalContentHeight <= availableScreenHeight {
        // 总高度没超过屏幕,让每个tableView适配自己的内容高度
        tableView1HeightConstraint.constant = tableView1ContentHeight
        tableView2HeightConstraint.constant = tableView2ContentHeight
        // 设置高优先级,确保约束生效
        tableView1HeightConstraint.priority = .defaultHigh
        tableView2HeightConstraint.priority = .defaultHigh
        // 关闭滚动,因为内容已经完全显示了
        tableView1.isScrollEnabled = false
        tableView2.isScrollEnabled = false
    } else {
        // 总高度超屏了,让两个tableView等高
        let equalHeight = (availableScreenHeight - tableViewSpacingConstraint.constant) / 2
        tableView1HeightConstraint.constant = equalHeight
        tableView2HeightConstraint.constant = equalHeight
        // 设置最高优先级,强制等高
        tableView1HeightConstraint.priority = .required
        tableView2HeightConstraint.priority = .required
        // 开启滚动,方便查看超出的内容
        tableView1.isScrollEnabled = true
        tableView2.isScrollEnabled = true
    }
    
    // 强制更新布局,让约束生效
    view.layoutIfNeeded()
}

你可以在这些地方调用这个方法:

  • viewDidLayoutSubviews(确保布局变化时更新)
  • 每次给tableView刷新数据后(比如tableView.reloadData()之后)

四、额外优化点

  • 如果你的tableView有表头或表尾,上面的calculateTableViewContentHeight方法已经通过sizeThatFits自动考虑了,不用额外处理;
  • 要是你用的是Objective-C,逻辑是一样的,只是语法转换一下就行;
  • 可以给tableView添加contentSize的监听(用KVO),当内容变化时自动调用updateTableViewHeights,这样更灵活。

内容的提问来源于stack exchange,提问作者Luis Gómez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:33:34