Is there a way to disable specific picker items? In AppKit, you can disable NSPopUpButton items via the NSMenuValidation protocol, but disabling a label in the picker predictably does nothing. Just another API gap in SwiftUI?
I tried:
Picker(selection: $viewModel.providerSelection, label: Text("Try using:")) {
ForEach(0..<Provider.allCases.count) {
Text(Provider.allCases[$0].rawValue.capitalized)
.disabled(true)
}
}
and there was no visual or interaction difference between disabling and not here.
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)
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With