UIViewRepresentable 不更新 swiftui 中的发布/绑定属性

UIViewRepresentable not updating Published / Binding properties in swiftui

我正在尝试将 UIScrollView 包装在 SwiftUI 中以获得一些额外的功能。我想访问 UIScrollView 的 contentOffset 属性 并将其分配给某些 属性(已发布 或绑定)在 SwiftUI 中,但 SwiftUI(我的 ContentView)未检测到任何 属性 更改。你能帮我把它弄好吗?

这是我的 UIScrollView

import SwiftUI
import UIKit

struct MyScrollView<Content: View>: UIViewRepresentable {
    
    @ObservedObject var viewModel: ViewModel
    @ViewBuilder var content: () -> Content
   
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    
    class Coordinator: NSObject, UIScrollViewDelegate {
        var parent: MyScrollView

        init(_ parent: MyScrollView) {
            self.parent = parent
        }
        
        func scrollViewDidScroll(_ scrollView: UIScrollView) {
           parent.viewModel.scrollviewContentOffset = scrollView.contentOffset.y
        }
        
    }
    
    func makeUIView(context: Context) -> UIScrollView {
        let scrollView = UIScrollView()
        
        scrollView.delegate = context.coordinator
        scrollView.isScrollEnabled = true
        
        let child = UIHostingController(rootView: content())
        scrollView.addSubview(child.view)
        
        let newSize = child.view.sizeThatFits(CGSize(width: UIScreen.screenWidth, height: UIScreen.screenHeight))
        child.view.frame = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)
        
        scrollView.contentSize = newSize
        
        return scrollView
    }
    
    func updateUIView(_ uiView: UIScrollView, context: Context) {
        //
    }
    
    typealias UIViewType = UIScrollView
}

这是我的 ContentView

import SwiftUI

class ViewModel: ObservableObject {
    @Published var scrollviewContentOffset = CGFloat.zero
}

struct ContentView: View {
    
    @StateObject private var viewModel = ViewModel()
    
    var body: some View {
        MyScrollView(viewModel: viewModel) {
            ForEach(0..<100) { i in
                Text("\(i)")
                    .offset(y: viewModel.scrollviewContentOffset / CGFloat(i + 1)
            }
        }
    }
}

您仅在创建 MyScrollView 时捕获初始 content,而不是在视图模型更改时更新它。

您需要在 updateUIView 内设置更新 content。例如,您可以将 hostingController 存储在 Coordinator:

struct MyScrollView<Content: View>: UIViewRepresentable {

    @StateObject var viewModel: ViewModel
    @ViewBuilder var content: () -> Content

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    class Coordinator: NSObject, UIScrollViewDelegate {
        let parent: MyScrollView
        var hostingController: UIHostingController<Content>!

        init(_ parent: MyScrollView) {
            self.parent = parent
        }

        func scrollViewDidScroll(_ scrollView: UIScrollView) {
            parent.viewModel.scrollviewContentOffset = scrollView.contentOffset.y
        }

    }

    func makeUIView(context: Context) -> UIScrollView {
        let scrollView = UIScrollView()

        scrollView.delegate = context.coordinator
        scrollView.isScrollEnabled = true

        let child = UIHostingController(rootView: content())
        context.coordinator.hostingController = child
        scrollView.addSubview(child.view)

        let newSize = child.view.sizeThatFits(CGSize(width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height))
        child.view.frame = CGRect(x: 0, y: 0, width: newSize.width, height: newSize.height)

        scrollView.contentSize = newSize

        return scrollView
    }

    func updateUIView(_ uiView: UIScrollView, context: Context) {
        context.coordinator.hostingController.rootView = content()
    }
}