与 NSViewRepresentable 托管的 NSScrollView 绑定的问题

Posted

技术标签:

【中文标题】与 NSViewRepresentable 托管的 NSScrollView 绑定的问题【英文标题】:Problem With Bindings with an NSViewRepresentable hosted NSScrollView 【发布时间】:2021-08-03 07:11:23 【问题描述】:

我正在尝试制作一个简单的 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")
    

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)
            
        
    


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

谁能看到我做错了什么?谢谢!

【问题讨论】:

【参考方案1】:

它是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)
                    
             
         
    

【讨论】:

再次感谢 Asperi - 我需要很长时间才能弄清楚这一点。我对 offset var 的 didSet 的意图是将值发送到其他地方。如果其他人想知道如何做到这一点,有很多方法可以做到这一点,如下所述:***.com/questions/56550713/…

以上是关于与 NSViewRepresentable 托管的 NSScrollView 绑定的问题的主要内容,如果未能解决你的问题,请参考以下文章

SwiftUI NSViewRepresentable 无法从@Publisher 读取数据

浅析C#中的托管非托管堆栈与垃圾回收

浅析C#中的托管非托管堆栈与垃圾回收

c# 托管与非托管

托管资源与非托管资源的定义

[转]托管代码与非托管代码