I'm writing a macOS app using SwiftUI, specifically, I'm adding a menu to the menu bar. The menu should have a selectable item -- item can have an optional checkmark in front of it -- and a shortcut. I cannot get it to work. It seems like you can either have a shortcut assigned -- you place a Button in the menu and attach the shortcut to the Button.
Button(String("Test")) {}
.keyboardShortcut("1")
Or, you can have the item to be selectable -- you place a Button() into a Picker and set up the selection binding and the Button tag correctly.
Picker(selection: $selection) {
Button(String("Test 1")) {}
.tag(1)
}.pickerStyle(.inline)
But, not both. As soon as you put a Button with the shortcut into a Picker, the shortcut disappears.
Picker(selection: $selection) {
Button(String("Test")) {}
.keyboardShortcut("1") // << ignored
.tag(1)
}.pickerStyle(.inline)
Am I missing something here or is this a known bug in SwiftUI? macOS 13.4.1, deployment target 12.0
I don't think keyboard shortcuts on a Picker
is currently supported. See also these related posts for people with similar situations: 1, 2.
As the first post says, you can use a bunch of Toggle
s instead, though you would have to handle updating the states of other toggles yourself, so that no two toggles are on at the same time.
Example:
struct ToggleState: Identifiable, Hashable {
var isOn = false
let id: Int
let shortcut: KeyboardShortcut
}
@State var toggles = [
ToggleState(isOn: true, id: 0, shortcut: .init("A")),
ToggleState(id: 1, shortcut: .init("B")),
ToggleState(id: 2, shortcut: .init("C")),
]
var body: some View {
ForEach(Array(toggles.indices), id: \.self) { i in
Toggle("\(toggles[i].id)", isOn: Binding(get: {
toggles[i].isOn
}, set: { _ in
for j in toggles.indices {
toggles[j].isOn = false
}
toggles[i].isOn = true
}))
.keyboardShortcut(toggles[i].shortcut)
}
}