I tried to reimplement the SegmentedControlers that I was using as they became deprecated in Xcode 11 beta 5. It took a while but I got the look I wanted. However when I replaced the tapAction with an onTapGesture() then the picker stopped working.
The code below shows the problem. Commenting out the pickerStyle gets a wheel picker which does work with onTapGesture()
import SwiftUI
var oneSelected = false
struct ContentView: View {
@State var sel = 0
var body: some View {
VStack {
Picker("Test", selection: $sel) {
Text("A").tag(0)
Text("B").tag(1)
Text("C").tag(2)
}
.pickerStyle(SegmentedPickerStyle())
Picker("Test", selection: $sel) {
Text("A").tag(0)
Text("B").tag(1)
Text("C").tag(2)
}
.pickerStyle(SegmentedPickerStyle())
.onTapGesture(perform: {
oneSelected = (self.sel == 1)
})
Text("Selected: \(sel)")
}
}
}
#if DEBUG
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif
I expect that Picker().pickerStyle(SegmentedPickerStyle()) should work the same way as SegmentedController() did.
The tapGesture
you added interferes with the picker's built in tap gesture recognizing, which is why the code in your .onTapGesture
runs when the picker is tapped, but the picker itself is not responding to taps. In your case, I suggest a different approach: pass a view model that conforms to ObservableObject
into your ContentView
, and have it contain an @Published
variable for the picker selection. Then add a property observer to that variable that checks if the selected option is 1.
For example:
class ViewModel: ObservableObject {
@Published var sel = 0 {
didSet {
oneSelected = oldValue == 1
}
}
var oneSelected = false
}
In SceneDelegate.swift
, or wherever ContentView
is declared:
ContentView().environmentObject(ViewModel())
In ContentView.swift
:
@EnvironmentObject var env: ViewModel
var body: some View {
VStack {
Picker("Test", selection: $env.sel) {
Text("A").tag(0)
Text("B").tag(1)
Text("C").tag(2)
}
.pickerStyle(SegmentedPickerStyle())
Picker("Test", selection: $env.sel) {
Text("A").tag(0)
Text("B").tag(1)
Text("C").tag(2)
}
.pickerStyle(SegmentedPickerStyle())
Text("Selected: \(sel)")
}
}
Note: In my experience, adding a tapGesture to a SegmentedControl
in previous betas resulted in the SegmentedControl
being unresponsive, so I'm not sure why it was working for you in previous version. As of SwiftUI beta 5, I don't think there is a way to assign priority levels to gestures.
Edit: You can use .highPriorityGesture()
to make your gesture take precedence over gestures defined in the view, but your gesture having higher precedence is causing your problem. You can, however, use .simultaneousGesture()
, which I thought would be the solution to your problem, but I don't think it is fully functional as of SwiftUI Beta 5.
class IndexManager: ObservableObject {
@Published var index = 0 {
didSet {
publisher.send(index)
}
}
let publisher = PassthroughSubject<Int, Never>()
}
struct SegmentedPickerView: View {
private let strings = ["a", "b", "c"]
@ObservedObject private var indexManager = IndexManager()
var body: some View {
Picker("", selection: $indexManager.index) {
ForEach(strings, id: \.self) {
Text($0).tag(self.strings.firstIndex(of: $0)!)
}
}.pickerStyle(SegmentedPickerStyle())
.onReceive(indexManager.publisher) { int in
print("onReceive \(int)")
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With