I am creating a picker in a form in SwiftUI. On selection of a new element in picker, when the view pulls back to the form, the picker row isn't getting deselected. Here is a screenshot of what I mean, the picker row remains grayed out like this.
I read some previous answers which say that this was a bug in Xcode 11.3, however, I'm running Xcode 12 beta 4 and am not sure if this is still a bug.
This is how I'm creating the picker:
struct SettingsView: View {
@State private var currentSelection = 1
var body: some View {
NavigationView {
Form {
Section {
Picker("Test 2", selection: $currentSelection) {
ForEach(1 ...< 100) { i in
Text(String(i)).tag(i)
}
}
}
}
}
}
}
Here is my ContentView, from which I am presenting SettingsView:
enum ActiveSheet: Identifiable {
case photoPicker, settings
var id: Int {
self.hashValue
}
}
struct ContentView: View {
@State var activeSheet: ActiveSheet?
var body: some View {
NavigationView {
VStack {
Text("Hello world")
Button("Select Photo") {
self.activeSheet = .photoPicker
}
}
.navigationBarTitle(Text("Title"), displayMode: .inline)
.navigationBarItems(trailing: Button(action: {
self.activeSheet = .settings
}, label: {
Image(systemName: "gear")
.imageScale(.large)
}))
}
.sheet(item: $activeSheet) { item in
if item == .photoPicker {
ImagePicker(selectedImage: $image, sourceType: .photoLibrary)
} else {
SettingsView()
}
}
}
}
Edit: I created a brand new project, this is the only code:
import SwiftUI
struct ContentView: View {
@State private var currentSelection = 0
var body: some View {
NavigationView {
Form {
Section {
Picker("Test Picker", selection: $currentSelection) {
ForEach(0 ..< 100) { i in
Text(String(i)).tag(i)
}
}
}
}.navigationBarTitle(Text("Test"))
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
The issue still persists.
(For the record I am on Big Sur, Xcode 12.2 and this issue is still there.)
After few tests it appears that this behaviour is due to multiple lists inside the same View. You can see that the first "List" (i.e. UITableView) gets its selected row deselected when the navigation stack is popped back to the view, but this doesn't work for the lists after the first one. So clearly this is a bug (in SwiftUI?!).
The only way (and somehow a crappy way) I have found to circumvent this bug is to have the Introspect Library get the tableView of interest (in this case the one displaying the Form) and do some housekeeping like this:
import Introspect
...
public class Weak<T: AnyObject> {
public weak var value: T?
public init(_ value: T? = nil) {
self.value = value
}
}
private var listTableView = Weak<UITableView>()
var body: Some View {
NavigationView {
VStack {
List {
...
}
Form {
Picker(...) {
...
}
}
.introspectTableView { listTableView.value = $0 }
.onAppear() {
if let tableView = listTableView.value, let indexPath = tableView.indexPathForSelectedRow {
tableView.deselectRow(at: indexPath, animated: true)
}
}
}
It works... but with no animation though (anyone?).
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