Testing this piece of code with Xcode 14 beta 5. Everything is working properly (sorting items with an animation, plus saving the selected sortOrder
in UserDefaults
).
However the if-else
condition in the Menu
's label seems to be ignored and the label is not updated. Please do you know why?
struct ContentView: View {
enum SortOrder: String, CaseIterable, Identifiable {
case forward
case reverse
var id: Self {
self
}
static let `default`: Self = .forward
var label: String {
switch self {
case .forward: return "Sort (forward)"
case .reverse: return "Sort (reverse)"
}
}
}
@AppStorage("sortOrder") var sortOrder: SortOrder = .default {
didSet {
sort()
}
}
@State private var items = ["foo", "bar", "baz"]
@ToolbarContentBuilder
var toolbar: some ToolbarContent {
ToolbarItem {
Menu {
ForEach(SortOrder.allCases) { sortOrder in
Button {
withAnimation { self.sortOrder = sortOrder }
} label: {
// FIXME: doesn't reflect sortOrder value
if sortOrder == self.sortOrder {
Label(sortOrder.label, systemImage: "checkmark")
} else {
Text(sortOrder.label)
}
}
}
} label: {
Label("Actions", systemImage: "ellipsis.circle")
}
}
}
var body: some View {
NavigationStack {
List(items, id: \.self) { item in
Text(item)
}
.navigationTitle("Test")
.toolbar { toolbar }
.onAppear(perform: sort)
}
}
func sort() {
switch sortOrder {
case .forward:
items.sort(by: <)
case .reverse:
items.sort(by: >)
}
}
}
CodePudding user response:
The if-else
in your ToolbarItem
is working correctly. The problem here is that .labelStyle
in a toolbar are defaulted to .titleOnly
.
To display the label with both icon and title, you would need to add .labelStyle(.titleAndIcon)
.
CodePudding user response:
It is selected but Menu
is not updated, assuming in toolbar it should be persistent.
A possible workaround is to force-rebuild menu on sort change, like
Menu {
// ...
} label: {
Label("Actions", systemImage: "ellipsis.circle")
}
.id(self.sortOrder) // << here !!
Tested with Xcode 14b5 / iOS 16