This seems currently not supported in pure SwiftUI. However, you can try wrapping NSPopUpButton
in NSViewRepresentable
, like this:
/// SwiftUI wrapper for NSPopUpButton which allows items to be disabled, which is currently not supported in SwiftUI's Picker
struct PopUpButtonPicker<Item: Equatable>: NSViewRepresentable {
final class Coordinator: NSObject {
private let parent: PopUpButtonPicker
init(parent: PopUpButtonPicker) {
self.parent = parent
}
@IBAction
func selectItem(_ sender: NSPopUpButton) {
let selectedItem = self.parent.items[sender.indexOfSelectedItem]
print("selected item \(selectedItem) at index=\(sender.indexOfSelectedItem)")
self.parent.selection = selectedItem
}
}
let items: [Item]
var isItemEnabled: (Item) -> Bool = { _ in true }
@Binding var selection: Item
let titleProvider: (Item) -> String
func makeCoordinator() -> Coordinator {
Coordinator(parent: self)
}
func makeNSView(context: Self.Context) -> NSPopUpButton {
let popUpButton = NSPopUpButton(frame: .zero, pullsDown: false)
popUpButton.autoenablesItems = false
popUpButton.target = context.coordinator
popUpButton.action = #selector(Coordinator.selectItem(_:))
for item in items.enumerated() {
popUpButton.addItem(withTitle: self.titleProvider(item.element))
// in order for this to work, autoenablesItems must be set to false
popUpButton.menu?.item(at: item.offset)?.isEnabled = self.isItemEnabled(item.element)
}
if let selectedIndex = self.items.firstIndex(where: { $0 == self.selection }) {
popUpButton.selectItem(at: selectedIndex)
}
return popUpButton
}
func updateNSView(_ view: NSPopUpButton, context: Self.Context) { }
}
// MARK: - Usage
struct ContentView: View {
private let items: [Int] = [1, 2, 3, 4, 5]
@State private var selectedValue: Int = 0
var body: some View {
PopUpButtonPicker(items: self.items, isItemEnabled: { $0 != 4 }, selection: self.$selectedValue, titleProvider: String.init)
}
}
Int
, as$0
. – Agma