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

SwiftUI Segmented Control Picker

I’m trying to implement a segmented picker with an additional behavior where tapping the selected option again deselects it. However, this code doesn’t seem to function as intended.

Picker("",selection: $selectedOption) {
    ForEach(["A","B","C","D","E"], id:\.self) { option in
        Text(option)
            .onTapGesture {
                if selectedOption == option {
                    selectedOption = ""
                }
            }
    }
}
.pickerStyle(.segmented)

>Solution :

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

This kind of behavior can be achieved by superimposing the selected option with an overlay and attaching the tap gesture to the overlay. When tapped, the selection can be de-selected.

One way to get the positioning right is to use .matchedGeometryEffect for placeholders in the background of the Picker. The ids used for matching should match the ids of the picker options:

struct ContentView: View {
    let options = ["A", "B", "C", "D", "E"]
    @State private var selectedOption = ""
    @Namespace private var ns
    var body: some View {
        Picker("", selection: $selectedOption) {
            ForEach(options, id:\.self) { option in
                Text(option)
            }
        }
        .pickerStyle(.segmented)
        .background {

            // A row of placeholders
            HStack(spacing: 0) {
                ForEach(options, id: \.self) { option in
                    Color.clear
                        .matchedGeometryEffect(id: option, in: ns, isSource: true)
                }
            }
        }
        .overlay {
            if selectedOption != "" {
                Color.clear
                    .contentShape(Rectangle())
                    .matchedGeometryEffect(id: selectedOption, in: ns, isSource: false)
                    .onTapGesture {
                        selectedOption = ""
                    }
            }
        }
    }
}

Animation

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