【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 根据父视图的高度正确调整。

相关推荐
青花瓷1 天前
虚拟机苹果OS当中XCode安装后如何增加对ios的支持
macos·ios·xcode
测试小小怪下士1 天前
Bug的严重等级和优先级别与分类
bug
测试小小怪下士1 天前
软件Bug和缺陷的区别是什么?
bug
树上有只程序猿3 天前
Go Web服务中如何优雅平滑重启?
前端·golang·xcode
Matrix703 天前
Spark_写ORALCE:ORA-01426 numeric overflow 问题解决
bug
#摩斯先生4 天前
Swift从0开始学习 函数和闭包 day2
ios·xcode·swift
hbblzjy5 天前
xcode-select: error: tool ‘xcodebuild‘ requires Xcode, but active developer
ide·macos·xcode·xcode-select·xcodebuild
明耀5 天前
WPF Gif图谱 如果隐藏的话会存在BUG
c#·bug·wpf
|Ringleader|6 天前
【Unity Bug 随记】unity version control 报 xx is not in a workspace.
unity·bug·版本管理·uvc
a1111111111ss6 天前
猫狗识别之BUG汇总
bug