Swiftui 使用NSVIEW Representable包装NSCOMBOX需要什么接线代码?
我正在尝试用NSViewRepresentable包装NSComboBox,以便在SwiftUI中使用。我想将下拉选项列表和组合框的文本值作为绑定传入。我希望文本值绑定在每次击键和选择一个下拉选项时更新。如果绑定在外部更改,我还希望组合框的文本值/选择发生更改 现在,我看不到选项选择的绑定更新,更不用说每次击键了,代码底部的SwiftUI预览显示了这一点 我阅读旧文档的最新线索是,可能在NSCOMBOX中,选择值和文本值是两个不同的属性,我编写了这个包装,好像它们是一个相同的属性?试着把它弄下来。出于我的目的,它们将是相同的,或者至少只有文本值才重要:它是用于任意用户字符串输入的表单字段,也有一些预设字符串 这是代码。我认为这应该可以粘贴到Mac平台游乐场文件中:Swiftui 使用NSVIEW Representable包装NSCOMBOX需要什么接线代码?,swiftui,appkit,nscombobox,nsviewrepresentable,Swiftui,Appkit,Nscombobox,Nsviewrepresentable,我正在尝试用NSViewRepresentable包装NSComboBox,以便在SwiftUI中使用。我想将下拉选项列表和组合框的文本值作为绑定传入。我希望文本值绑定在每次击键和选择一个下拉选项时更新。如果绑定在外部更改,我还希望组合框的文本值/选择发生更改 现在,我看不到选项选择的绑定更新,更不用说每次击键了,代码底部的SwiftUI预览显示了这一点 我阅读旧文档的最新线索是,可能在NSCOMBOX中,选择值和文本值是两个不同的属性,我编写了这个包装,好像它们是一个相同的属性?试着把它弄下来
导入应用工具包
导入快捷键
公共结构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期权