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)
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.
.matchedGeometryEffect
..matchedGeometryEffect
, but it does work to use invisible placeholders in the background..contentShape
to the clear overlay, to make it receptive to tap gestures.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 = ""
}
}
}
}
}