Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Picker Row not getting deselected in Form (SwiftUI, Xcode 12 beta 4)

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. enter image description here

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.

like image 599
Aryan C Avatar asked Aug 08 '20 11:08

Aryan C


1 Answers

(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?).

like image 98
user3124975 Avatar answered Oct 17 '22 02:10

user3124975