【ios】SwiftUI 混用 UIKit 的 Bug 解决:UITableView 无法滚动到底部

问题描述

在 SwiftUI 中嵌套使用 UIKit 的 UITableView 时,你可能会遇到一个常见的 Bug:UITableView 的高度没有正确设置,导致内容无法正常滚动,尤其是滚动到页面底部时。

核心问题 在于 SwiftUI 和 UIKit 的布局机制不同。SwiftUI 使用声明式布局系统,而 UIKit 使用传统的视图层次结构。如果没有明确告诉 UITableView 应该占用多少高度,UIKit 中的 UITableView 可能会默认按照父视图的尺寸计算,忽略 SwiftUI 布局中的其他组件。因此,UITableView 的高度和滚动行为就会出现问题。

解决思路

为了让 UITableView 在 SwiftUI 布局中能够正确滚动到底,我们需要:

  1. 动态获取 SwiftUI 中的可用高度 ,通过 SwiftUI 的 GeometryReader 计算当前布局的高度。
  2. 将高度传递给 UIKit 中的 UITableView,确保它根据父视图的高度动态调整。

以下是一个解决该问题的demo示例

1. 使用 UIViewControllerRepresentable 桥接 SwiftUI 和 UIKit

我们首先需要创建一个桥接类,让 SwiftUI 能够嵌套 UIKit 组件。在这个桥接类中,我们接收从 SwiftUI 获取的高度,然后在 UIKit 组件中使用这个高度动态调整 UITableView 的大小。

swift 复制代码
import SwiftUI

struct MyTableViewWrapper: UIViewControllerRepresentable {
    var height: CGFloat // 接收传递过来的高度

    func makeUIViewController(context: Context) -> MyTableViewController {
        let controller = MyTableViewController()
        controller.height = height // 设置高度
        return controller
    }

    func updateUIViewController(_ uiViewController: MyTableViewController, context: Context) {
        uiViewController.height = height // 动态更新高度
    }
}

MyTableViewWrapper 作为 SwiftUI 和 UIKit 的桥接类,它允许我们将 SwiftUI 的布局数据(比如高度)传递给 UIKit 中的 UITableView

2. 在 UIViewController 中调整 UITableView 的高度

在自定义的 UIViewController 中,我们使用传入的高度来设置 UITableView 的 frame,这样可以确保 UITableView 的大小根据 SwiftUI 的布局进行动态调整。

swift 复制代码
import UIKit

class MyTableViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    var height: CGFloat = 0 // 用于接收传进来的高度
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // 创建 UITableView,并根据传入的高度调整它的大小
        let tableView = UITableView(frame: CGRect(x: 0, y: 0, width: view.bounds.width, height: height), style: .plain)
        tableView.dataSource = self
        tableView.delegate = self
        view.addSubview(tableView)
    }

    // UITableViewDataSource 协议实现
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 20
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell(style: .default, reuseIdentifier: "cell")
        cell.textLabel?.text = "Row \(indexPath.row)"
        return cell
    }
}

在这个自定义的 UIViewController 中,UITableView 的高度由外部传入并动态调整,这样就避免了 UITableView 默认假设自己占据全屏的问题。

3. 使用 GeometryReader 获取 SwiftUI 中的高度

接下来,我们需要在 SwiftUI 布局中使用 GeometryReader 来动态获取可用的高度,并将其传递给 UIKit 的 UITableView

swift 复制代码
struct ContentView: View {
    var body: some View {
        GeometryReader { geometry in
            VStack {
                Text("这里是一些顶部内容")
                    .padding()

                // 将当前视图的高度传递给 UIKit 中的 TableView
                MyTableViewWrapper(height: geometry.size.height * 0.6) // 比如占屏幕60%高度

                Spacer()
            }
            .padding()
        }
    }
}

在这个布局中,GeometryReader 会动态计算当前视图的高度,并将这个高度传递给 MyTableViewWrapper,从而确保 UITableView 根据父视图的高度正确调整。

相关推荐
宁酱醇7 小时前
各种各样的bug合集
开发语言·笔记·python·gitlab·bug
有什么东东7 小时前
山东大学软件学院创新项目实训开发日志(20)之中医知识问答自动生成对话标题bug修改
java·vue·bug·springboot
littleplayer7 小时前
iOS 中的 @MainActor 详解
前端·swiftui·swift
软件技术NINI8 小时前
详解BUG(又名:BUG的生命周期)
bug
cauyyl9 小时前
xcode 16 遇到contains bitcode
react native·xcode
A_ugust__9 小时前
Vue3集成浏览器API实时语音识别
人工智能·语音识别·xcode
兮动人10 小时前
Idea使用github copilot登录bug+解决方案
github·bug·intellij-idea
Macle_Chen10 小时前
ios开发中xxx.debug.dylib not found
ios·bug·debug.dylib
未来之窗软件服务12 小时前
声音分离人声和配乐-从头设计数字生命第5课, demucs——仙盟创梦IDE
ide·macos·xcode·仙盟创梦ide·数字生命
福大大架构师每日一题12 小时前
docker v28.1.1 正式发布!修复关键Bug,网络与安全性再升级
网络·docker·bug