NSViewRepresentable 托管 NSScrollView 的绑定问题

Pet*_*ter 5 swiftui

我正在尝试制作一个简单的 SWiftUI ScrollView,我可以在其中通过绑定设置和获取 ScrollView 边界偏移的值。我有以下内容,它可以作为 ScrollView 编译并正常工作,但我无法实际设置和获取偏移量并将其传播回托管 ScrollView 的 ContentView。

我有以下内容:

struct MyScrollView<Content>: NSViewRepresentable where Content: View {
    private var content: Content
    let offset: Binding<CGFloat>
    
    
    init(offset: Binding<CGFloat>, @ViewBuilder content: () -> Content) {
        self.content = content()
        self.offset = offset
    }


    func makeNSView(context: NSViewRepresentableContext<MyScrollView>) ->TheScrollView {
        let view = TheScrollView(offset: offset)
        
        view.hasVerticalScroller = true
        view.hasHorizontalScroller = true
    
        let document = NSHostingView(rootView: content)
        document.translatesAutoresizingMaskIntoConstraints = false
        view.documentView = document
 
        return view
    }

    
    func updateNSView(_ view: TheScrollView, context: NSViewRepresentableContext<MyScrollView>) {
    }
    
}


class TheScrollView: NSScrollView, ObservableObject{
    private var subscriptions: Set<AnyCancellable> = []
    var offset: Binding<CGFloat>
    
    init(offset: Binding<CGFloat>){
        self.offset = offset
        
        super.init(frame: .zero)

        NotificationCenter.default
            .publisher(for: NSScrollView.boundsDidChangeNotification, object: self.contentView.documentView)
            .sink() { _ in
                let view = self.contentView
                print(view.bounds.origin.y)                     // <- I do get this
                self.offset.wrappedValue = view.bounds.origin.y // This does nothing
            }
            .store(in: &subscriptions)
    }
    
    required init?(coder: NSCoder){
        fatalError("init(coder:) has not been implemented")
    }
}
Run Code Online (Sandbox Code Playgroud)

MyScrollView 托管在 contentView 中,如下所示:

import SwiftUI
import Combine

struct ContentView: View{
    @State var offset: CGFloat = 10.0{
        didSet{
            print("Offset \(offset)")
        }
    }
    
    var body: some View{
        MyScrollView(offset: $offset){
            ZStack{
                Rectangle().foregroundColor(.clear).frame(width: 1200, height: 1000)
                Rectangle().foregroundColor(.blue).frame(width: 100, height: 100)
            }
        }
    }
}

Run Code Online (Sandbox Code Playgroud)

正如您所看到的,偏移值从@State var传递到MyScrollView,然后传递到TheScrollView,它是NSScrollView的子类。从那里我有一个简单的通知来获取边界更改并设置绑定。但是,设置绑定对绑定中的实际值没有任何作用,并且它绝对不会传播回 ContentView。另外,偏移量的地址改变了层次结构,所以看起来我正在将 Binding 到 Binding 传递到 TheScrollView 而不是原始绑定,但我似乎无法修复它。

谁能看到我做错了什么吗?

Asp*_*eri 4

它是State- 当在正文中使用时它会更新,因此请像下面这样使用:

演示

struct ContentView: View{
    @State var offset: CGFloat = 10.0

    var body: some View {
         VStack {
            Text("Offset: \(offset)")          // << here !!
             MyScrollView(offset: $offset){
                    ZStack{
                         Rectangle().foregroundColor(.clear).frame(width: 1200, height: 1000)
                         Rectangle().foregroundColor(.blue).frame(width: 100, height: 100)
                    }
             }
         }
    }
}
Run Code Online (Sandbox Code Playgroud)