如何使用 swiftUI 获取 ComboBox
Posted
技术标签:
【中文标题】如何使用 swiftUI 获取 ComboBox【英文标题】:How to get a ComboBox with swiftUI 【发布时间】:2021-06-13 09:02:32 【问题描述】:有没有办法在 SwiftUI 中创建 NSComboBox
?
当我使用Picker
时,在MacOS下会创建一个NSPopUpButton
。
我试过了:
var body: some View
Picker("Test:", selection: $selected)
ForEach(1..<10) i in
Text(String(i))
.padding()
但这会让我得到这个:
但我需要一个组合框,我可以在其中输入文本以及从列表中选择。
这在 SwiftUI 中是否可能没有将NSComboBox
集成为NSViewRepresentable
。
我已经检查了以下问题:SwiftUI Custom Picker / ComboBox 但它是关于自定义选择器而不是关于 NSComboBox。
【问题讨论】:
这能回答你的问题吗? SwiftUI Custom Picker / ComboBox @loremipsum:不,很遗憾不是。链接的问题与 NSComboBox 无关。 【参考方案1】:VDKComboBox
使用NSViewRepresentable
并没有我预期的那么糟糕。这是 SwiftUI 的 NSComboBox
的完整实现:
import Foundation
import SwiftUI
struct VDKComboBox: NSViewRepresentable
// The items that will show up in the pop-up menu:
var items: [String]
// The property on our parent view that gets synced to the current stringValue of the NSComboBox, whether the user typed it in or selected it from the list:
@Binding var text: String
func makeCoordinator() -> Coordinator
return Coordinator(self)
func makeNSView(context: Context) -> NSComboBox
let comboBox = NSComboBox()
comboBox.usesDataSource = false
comboBox.completes = false
comboBox.delegate = context.coordinator
comboBox.intercellSpacing = NSSize(width: 0.0, height: 10.0) // Matches the look and feel of Big Sur onwards.
return comboBox
func updateNSView(_ nsView: NSComboBox, context: Context)
nsView.removeAllItems()
nsView.addItems(withObjectValues: items)
// ComboBox doesn't automatically select the item matching its text; we must do that manually. But we need the delegate to ignore that selection-change or we'll get a "state modified during view update; will cause undefined behavior" warning.
context.coordinator.ignoreSelectionChanges = true
nsView.stringValue = text
nsView.selectItem(withObjectValue: text)
context.coordinator.ignoreSelectionChanges = false
// MARK: - Coordinator
extension VDKComboBox
class Coordinator: NSObject, NSComboBoxDelegate
var parent: VDKComboBox
var ignoreSelectionChanges: Bool = false
init(_ parent: VDKComboBox)
self.parent = parent
func comboBoxSelectionDidChange(_ notification: Notification)
if !ignoreSelectionChanges,
let box: NSComboBox = notification.object as? NSComboBox,
let newStringValue: String = box.objectValueOfSelectedItem as? String
parent.text = newStringValue
func controlTextDidEndEditing(_ obj: Notification)
if let textField = obj.object as? NSTextField
parent.text = textField.stringValue
使用它:
struct MyView: View
@State var comboBoxText: String = ""
var body: some View
VDKComboBox(items: ["one", "two", "three"], text: $comboBoxText)
.padding()
当然,您将动态填充项目列表;硬编码的字符串数组只是一个简单的例子。
替代方案
我确实意识到你明确排除了NSViewRepresentable
,但我尝试了很多其他方法来模仿NSComboBox
,包括:
Button
,.trailing
对齐
动态交换TextField
和Picker
自定义Popover
链接到TextField
所有这些都以某种方式看起来“陌生”。而且由于NSViewRepresentable
并没有那么糟糕,这就是我所决定的。将来它可能会对其他人有所帮助,因此即使您想要一个不依赖于 NSViewRepresentable
的实现,我也将我的实现放在这里。
【讨论】:
感谢您的回答,但我希望没有 NSViewRepresentable 也可以,因为该应用程序也应该在 ios 设备上运行,我想避免所有 #ifdef ;-) 啊。 NSComboBox 是一个 Mac 成语;我认为没有该控件的官方 iOS 版本。有一些第三方尝试,但大多数看起来都很笨拙。尽管如此,#ifdef 应该仅限于组合框文件,因此痛苦相对较小。每次使用自定义组合框时都不需要#ifdef。以上是关于如何使用 swiftUI 获取 ComboBox的主要内容,如果未能解决你的问题,请参考以下文章
SwiftUI 中如何获取任意视图触摸位置(全局或局部)的坐标
SwiftUI 中如何获取任意视图触摸位置(全局或局部)的坐标
SwiftUI 中如何获取任意视图触摸位置(全局或局部)的坐标