In SwiftUI, I have a Picker with a .segmented style that I use to select how a list is sorted. What I want is for each segment of that picker to reverse the sort order, in addition to its normal behaviour.
Below is an example of a list with a segmented control in the header that is used to change how such a list can be sorted:
struct ContentView: View {
@State private var animals = [
Animal(name: "Lion", number: 1),
Animal(name: "Monkey", number: 2),
Animal(name: "Elephant", number: 3),
]
@State private var sortOrder: SortOrder = .alphabetical
var body: some View {
List {
Section {
ForEach(animals) { animal in
HStack {
Text(animal.name)
Spacer()
Text("\(animal.number)")
}
}
} header: {
VStack(alignment: .leading, spacing: 0) {
Text("Sort:")
HStack {
Picker("Sorting methods", selection: $sortOrder) {
ForEach(SortOrder.allCases, id: \.self) { sortOrder in
Text(sortOrder.description)
}
}
.pickerStyle(.segmented)
}
}
.onChange(of: sortOrder) { sortOrder in
withAnimation {
sort(by: sortOrder)
}
}
.onAppear() {
sort(by: self.sortOrder)
}
}
}
.listStyle(.inset)
}
private func sort(by sortOrder: SortOrder) {
switch sortOrder {
case .alphabetical: return animals.sort(by: { $0.name < $1.name })
case .numerical: return animals.sort(by: { $0.number < $1.number })
}
}
}
struct Animal: Identifiable {
var id = UUID()
var name: String
var number: Int
}
enum SortOrder: CaseIterable {
case alphabetical
case numerical
var description: String {
switch self {
case .alphabetical: return "Alphabetical"
case .numerical: return "Numerical"
}
}
}
This all works fine: the list gets sorted by name or by number. What I want now is to reverse the sort order by tapping on a selected segment again. So for example, by tapping on segment 'alphanumeric' for the first time, the list is sorted A-Z. I want a second tap on that same segment to sort Z-A. Similar for numeric sorting.
Unfortunately, I don't get any notification that a segment is tapped for a second time. I tried using .onTapGesture
, but that a) interferes with the normal picker behaviour and b) only specifies that there was a tap somewhere on the picker, but not which segment was tapped.
I guess I could make my own custom picker, but I am trying to avoid that, because SwiftUI's picker does a great job otherwise. Except for the second tap, that is. :-).
Any ideas/suggestions are highly appreciated. Thanks!
try something like this, with a double tap on the picker buttons: