I'm trying to have a Section header inside a Menu for a Picker in mit SwiftUI application, but it does not show up:
enum Filter {
case upcoming, past
}
struct ContentView: View {
@State var filter = Filter.upcoming
var body: some View {
Menu("Example") {
Section("Foo") {
Text("Bar")
}
Section("Filter") {
Picker(selection: $filter, label: Text("Filter options")) {
Text("Upcoming events").tag(Filter.upcoming)
Text("Past events").tag(Filter.past)
}
}
Section("Order") {
Button("Ascending") {}
Button("Descending") {}
}
}
.menuOrder(.fixed)
}
}
Any idea how to get a section header above a Picker?

Starting with iOS 18.0, you can use the labelsVisibility(_:) modifier to ensure a section header is displayed for a Picker within a Menu.
enum Filter {
case upcoming, past
}
struct ContentView: View {
@State var filter = Filter.upcoming
var body: some View {
Menu("Example") {
Section("Foo") {
Text("Bar")
}
Picker(selection: $filter, label: Text("Filter options")) {
Text("Upcoming events")
.tag(Filter.upcoming)
Text("Past events")
.tag(Filter.past)
}
.labelsVisibility(.visible)
Section("Order") {
Button("Ascending") {}
Button("Descending") {}
}
}
.menuOrder(.fixed)
}
}
It seems that when the picker style is the default of .inline then the section header is always hidden.
Here are two possible workarounds.
1. Use picker style .menu
The section header is shown if you change the picker style to .menu. But then the picker is collapsed. So it's a compromise.
Section("Filter") {
Picker(selection: $events.filter, label: Text("Filter options")) {
Text("Upcoming events").tag(EventListRequest.Filter.upcoming)
Text("Past events").tag(EventListRequest.Filter.past)
}
.pickerStyle(.menu)
}

2. Use regular buttons with a custom LabelStyle
As another possible workaround, the individual picker items can simply be listed as regular buttons inside the Section. A custom LabelStyle can then be used to show a checkmark against the item that is selected.
This gives almost the same appearance as an inline Picker, except that the checkmark is on the right instead of on the left.
struct MyLabelStyle: LabelStyle {
let isSelected: Bool
func makeBody(configuration: Configuration) -> some View {
if isSelected {
configuration.icon
}
configuration.title
}
}
Section("Filter") {
Button { events.filter = .upcoming } label: {
Label("Upcoming events", systemImage: "checkmark")
.labelStyle(MyLabelStyle(isSelected: events.filter == .upcoming))
}
Button { events.filter = .past } label: {
Label("Past events", systemImage: "checkmark")
.labelStyle(MyLabelStyle(isSelected: events.filter == .past))
}
}

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