首页 > 解决方案 > Swift UI 中的自定义滚动视图内容大小

问题描述

我正在深入研究 SwiftUI,并尝试为 Scrollview 实现拉取刷新功能。据我所知,iOS 13 和 iOS14 都没有原生解决方案,所以我尝试使用 UIViewRepresentable 实现自定义滚动视图。

我在互联网上找到了一些代码,为我的应用程序采用了一些行,但我一直在为内容大小问题而苦苦挣扎。问题是,当我尝试调用自定义滚动视图时,它需要精确的宽度和高度,但我在内容视图中有 ForEach,它的高度可以是 500 或 15000,具体取决于单元格的数量,所以我希望 ScrollView 自动计算它的高度基于内容。

我的问题是,我怎样才能做到这一点?我尝试了不同的方法,但都没有奏效——我的滚动视图停止滚动,滚动视图中的内容移动到可见区域上方等。如果您知道解决方案,请提供帮助。

我的自定义滚动视图代码是

struct CustomScrollView<Content: View, VM: CustomViewModel>: UIViewRepresentable {
    func makeCoordinator() -> Coordinator {
        Coordinator(self, viewModel: viewModel)
    }

    var width: CGFloat
    var height: CGFloat
    let viewModel: VM
    let content: () -> Content

    init(width: CGFloat, height: CGFloat, viewModel: VM, @ViewBuilder content: @escaping () -> Content) {
        self.width = width
        self.height = height
        self.viewModel = viewModel
        self.content = content
    }

    func makeUIView(context: Context) -> UIScrollView {
        let control = UIScrollView()
        control.refreshControl = UIRefreshControl()
        control.refreshControl?.addTarget(context.coordinator,
                                          action: #selector(Coordinator.handleRefreshControl), for: .valueChanged)

        let childView = UIHostingController(rootView: content())
        childView.view.frame = CGRect(x: 0, y: 0, width: width, height: height)
        control.addSubview(childView.view)
        control.contentSize = CGSize(width: width, height: height)
        
        return control
    }

    func updateUIView(_ uiView: UIScrollView, context: Context) { }

    class Coordinator: NSObject {
        var control: CustomScrollView<Content, VM>
        var viewModel: VM

        init(_ control: CustomScrollView, viewModel: VM) {
            self.control = control
            self.viewModel = viewModel
        }

        @objc func handleRefreshControl(sender: UIRefreshControl) {
            sender.endRefreshing()
            print("refreshed")
        }
    }
}

我在我的 SwiftUI 视图中这样称呼它

GeometryReader { geometry in
        CustomScrollView(
            width: geometry.size.width,
            height: 20000,
            viewModel: viewModel) {
            TaskListMainView(presenter: presenter, viewModel: viewModel)
        }

当我这样称呼它时,一个屏幕看起来很棒,因为它与高度大致匹配,但另一个屏幕只是在屏幕上延伸,看起来像一团糟。

如何计算 scrollView 内内容的高度以使其适合正确的大小和滚动?

我的 TaskListMainView 由 VStack 和 Picker 和 ForEach 表组成。

标签: iosswiftswiftui

解决方案


推荐阅读