Swiftui 使用NSVIEW Representable包装NSCOMBOX需要什么接线代码?

Swiftui 使用NSVIEW Representable包装NSCOMBOX需要什么接线代码?,swiftui,appkit,nscombobox,nsviewrepresentable,Swiftui,Appkit,Nscombobox,Nsviewrepresentable,我正在尝试用NSViewRepresentable包装NSComboBox,以便在SwiftUI中使用。我想将下拉选项列表和组合框的文本值作为绑定传入。我希望文本值绑定在每次击键和选择一个下拉选项时更新。如果绑定在外部更改,我还希望组合框的文本值/选择发生更改 现在,我看不到选项选择的绑定更新,更不用说每次击键了,代码底部的SwiftUI预览显示了这一点 我阅读旧文档的最新线索是,可能在NSCOMBOX中,选择值和文本值是两个不同的属性,我编写了这个包装,好像它们是一个相同的属性?试着把它弄下来

我正在尝试用NSViewRepresentable包装NSComboBox,以便在SwiftUI中使用。我想将下拉选项列表和组合框的文本值作为绑定传入。我希望文本值绑定在每次击键和选择一个下拉选项时更新。如果绑定在外部更改,我还希望组合框的文本值/选择发生更改

现在,我看不到选项选择的绑定更新,更不用说每次击键了,代码底部的SwiftUI预览显示了这一点

我阅读旧文档的最新线索是,可能在NSCOMBOX中,选择值和文本值是两个不同的属性,我编写了这个包装,好像它们是一个相同的属性?试着把它弄下来。出于我的目的,它们将是相同的,或者至少只有文本值才重要:它是用于任意用户字符串输入的表单字段,也有一些预设字符串

这是代码。我认为这应该可以粘贴到Mac平台游乐场文件中:

导入应用工具包
导入快捷键
公共结构ComboBoxRepresentable:NSViewRepresentable{
私有var选项:绑定
私有变量文本:绑定
public init(选项:绑定,文本:绑定){
self.options=选项
self.text=文本
}
public func makeNSView(上下文:context)->NSComboBox{
让comboBox=NSComboBox()
comboBox.delegate=context.coordinator
comboBox.usesDataSource=true
comboBox.dataSource=context.coordinator
返回组合框
}
public func updateNSView(uComboBox:NSComboBox,context:context){
comboBox.stringValue=text.wrappedValue
comboBox.reloadData()
}
}
可表示的公共扩展{
最终类协调器:NSObject{
var选项:绑定
var文本:绑定
init(选项:绑定,文本:绑定){
self.options=选项
self.text=文本
}
}
func makeCoordinator()->Coordinator{
协调器(选项:选项,文本:文本)
}
}
扩展ComboxRepresentable。协调器:nsComboxDelegate{
公共函数组合框SelectionDidChange(u通知:通知){
guard let comboBox=notification.object as?NSComboBox else{return}
text.wrappedValue=comboBox.stringValue
}
}
扩展ComboxRepresentable。协调器:nsComboxDataSource{
public func组合框(comboBox:NSComboBox,objectValueForItemAt index:Int)->有吗{
guard options.wrappedValue.index.contains(index)else{return nil}
返回选项。wrappedValue[索引]
}
public func numberOfItems(在组合框中:NSComboBox)->Int{
options.wrappedValue.count
}
}
#如果调试
结构ComboboxRepresentablePreviewRapper:视图{
@国家私有var text=“四”
var body:一些观点{
VStack{
文本(“选择:\(文本)”)
可代表的(
选项:。常量([“一”,“二”,“三]),
text:$text
)
}
}
}
结构ComboBoxRepresentable_预览:PreviewProvider{
@国家私有变量text=“”
静态var预览:一些视图{
ComboboxRepresentablePreviewRapper()
.框架(宽:200,高:100)
}
}
#恩迪夫
如果您有任何建议,请提前感谢

公共结构ComboBoxRepresentable:NSViewRepresentable{
public struct ComboBoxRepresentable: NSViewRepresentable {
    //If the options change the parent should be an @State or another source of truth if they don't change just remove the @Binding
    @Binding private var options: [String]
    @Binding private var text: String
    public init(options: Binding<[String]>, text: Binding<String>) {
        self._options = options
        self._text = text
    }
    
    public func makeNSView(context: Context) -> NSComboBox {
        let comboBox = NSComboBox()
        comboBox.delegate = context.coordinator
        comboBox.usesDataSource = true
        comboBox.dataSource = context.coordinator
        comboBox.stringValue = text
        comboBox.reloadData()
        return comboBox
    }
    
    public func updateNSView(_ comboBox: NSComboBox, context: Context) {
        //You don't need anything here the delegate updates text and the combobox is already updated
    }
}

public extension ComboBoxRepresentable {
    final class Coordinator: NSObject {
        //This is a much simpler init and injects the new values directly int he View vs losing properties in a class updates can be unreliable
        var parent: ComboBoxRepresentable
        init(_ parent: ComboBoxRepresentable) {
            self.parent = parent
        }
    }
    
    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
}

extension ComboBoxRepresentable.Coordinator: NSComboBoxDelegate {
    
    public func comboBoxSelectionDidChange(_ notification: Notification) {
        guard let comboBox = notification.object as? NSComboBox else { return }
        //It is a known issue that this has to be ran async for it to have the current value
        //https://stackoverflow.com/questions/5265260/comboboxselectiondidchange-gives-me-previously-selected-value
        DispatchQueue.main.async {
            self.parent.text = comboBox.stringValue
        }
    }
    
}

extension ComboBoxRepresentable.Coordinator: NSComboBoxDataSource {
    
    public func comboBox(_ comboBox: NSComboBox, objectValueForItemAt index: Int) -> Any? {
        guard parent.options.indices.contains(index) else { return nil }
        return parent.options[index]
    }
    
    public func numberOfItems(in comboBox: NSComboBox) -> Int {
        parent.options.count
    }
}

#if DEBUG
struct ComboBoxRepresentablePreviewWrapper: View {
    @State private var text = "four"
    //If they dont update remove the @Binding
    @State private var options = ["one", "two", "three"]
    var body: some View {
        VStack {
            Text("selection: \(text)")
            
            ComboBoxRepresentable(
                options: $options,
                text: $text
            )
        }
    }
}

struct ComboBoxRepresentable_Previews: PreviewProvider {
    @State private var text = ""
    static var previews: some View {
        ComboBoxRepresentablePreviewWrapper()
            .frame(width: 200, height: 100)
    }
}
#endif
//如果选项发生更改,则父级应该是@State,如果不更改,则应该是另一个真相来源,只需删除@Binding即可 @绑定私有变量选项:[字符串] @绑定私有变量文本:字符串 public init(选项:绑定,文本:绑定){ self.\u options=选项 self.\u text=文本 } public func makeNSView(上下文:context)->NSComboBox{ 让comboBox=NSComboBox() comboBox.delegate=context.coordinator comboBox.usesDataSource=true comboBox.dataSource=context.coordinator comboBox.stringValue=文本 comboBox.reloadData() 返回组合框 } public func updateNSView(uComboBox:NSComboBox,context:context){ //在这里您不需要任何东西—代理更新文本,组合框已经更新 } } 可表示的公共扩展{ 最终类协调器:NSObject{ //这是一个简单得多的初始化,直接在视图中注入新值,而在类更新中丢失属性是不可靠的 变量父项:ComboBoxRepresentable init(uuParent:ComboBoxRepresentable){ self.parent=parent } } func makeCoordinator()->Coordinator{ 协调员(自我) } } 扩展ComboxRepresentable。协调器:nsComboxDelegate{ 公共函数组合框SelectionDidChange(u通知:通知){ guard let comboBox=notification.object as?NSComboBox else{return} //这是一个已知的问题,它必须异步运行才能具有当前值 //https://stackoverflow.com/questions/5265260/comboboxselectiondidchange-gives-me-previously-selected-value DispatchQueue.main.async{ self.parent.text=comboBox.stringValue } } } 扩展ComboxRepresentable。协调器:nsComboxDataSource{ public func组合框(comboBox:NSComboBox,objectValueForItemAt index:Int)->有吗{ 保护parent.options.index.contains(index)else{return nil} 返回parent.options[索引] } public func numberOfItems(在组合框中:NSComboBox)->Int{ parent.options.count } } #如果调试 结构ComboboxRepresentablePreviewRapper:视图{ @国家私有var text=“四” //如果他们不更新,请删除@Binding @国有-私有var期权