最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

swift - SwiftUI Segmented Control Picker - Stack Overflow

programmeradmin2浏览0评论

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)

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)
Share Improve this question edited Nov 19, 2024 at 13:15 Benzy Neez 24.1k3 gold badges16 silver badges46 bronze badges asked Nov 19, 2024 at 13:01 loonnloonn 31 bronze badge 1
  • Assuming this is iOS, you need to subclass UISegmentedControl (see here) and write a UIViewRepresentable wrapping it, or build your own picker from scratch. – Sweeper Commented Nov 19, 2024 at 13:06
Add a comment  | 

1 Answer 1

Reset to default 0

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.
  • It doesn't work to use the text labels themselves as the source for .matchedGeometryEffect, but it does work to use invisible placeholders in the background.
  • Use the ids of the picker options as the ids for matching.
  • Apply a .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 = ""
                    }
            }
        }
    }
}

发布评论

评论列表(0)

  1. 暂无评论