Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How to build sort direction in menu like Files app?

I’m displaying sort options in my Menu, but I’d also like the user to control the sort direction in the way the Files app works: tapping a second time toggles the sort direction.

enter image description here

Here’s what I have:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

@State private var selectedSort: SortOption = .name
@State private var isSortAscending = true

enum SortOption {
    case name
    case number
    case length
}

Menu {
    Picker(selection: $selectedSort, label: Text("Sorting options")) {
        Button {
            isSortAscending.toggle()
        } label: {
            HStack {
                Text("Name")
                Spacer()
                Image(systemName: isSortAscending ? "chevron.down" : "chevron.up")
            }
        }
        .tag(SortOption.name)
        Button {
            isSortAscending.toggle()
        } label: {
            HStack {
                Text("Number")
                Spacer()
                Image(systemName: isSortAscending ? "chevron.down" : "chevron.up")
            }
        }
        .tag(SortOption.number)
        Button {
            isSortAscending.toggle()
        } label: {
            HStack {
                Text("Length")
                Spacer()
                Image(systemName: isSortAscending ? "chevron.down" : "chevron.up")
            }
        }
        .tag(SortOption.length)
    }
}

Tapping doesn’t toggle the sort state at all. Is there a better or more supported way to do this?

>Solution :

Item selected is handled internally, so we need selection side-effect. It is possible to do by injecting will-set side effect in computable binding.

Here is a possible approach tested with Xcode 13.4 / iOS 15.5

demo

Main part:

var sorting: Binding<SortOption> { .init(
    get: { self.selectedSort },
    set: {
        if self.selectedSort == $0 {
            self.isSortAscending.toggle()
        }
        self.selectedSort = $0
    }
)}

var body: some View {
    Menu("Sort") {
        Picker(selection: sorting, label: Text("Sorting options")) {
            ForEach(SortOption.allCases) { option in
                HStack {
                    Text(option.rawValue)
                    Spacer()
                    if selectedSort == option {
                        Image(systemName: isSortAscending ? "chevron.down" : "chevron.up")
                    }

Test module on GitHub

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading