swiftuiswiftui-stateswiftui-ontapgesture

Swift UI @State does get set on the first tap


I have a simple list of for a Custom View. What needs to happen is when one of the items are selected it needs to show the detail view for that item. In my code, when I select an item for the very first time, the @Statet selectedListener does not get set so the detail view does not appear. If I keep selecting the same item that was previously selected the behaviour remains the same. However, if I select a different item, it works properly and I can come back to the previous item and view its detail view without an issue. Its such a simple thing I'm trying to do and just can't figure out what I'm may be doing wrong. Any help would be appreciated. Thank You.

struct ListenersListView<Model>: View where Model: ActiveListenerViewModel {

@ObservedObject var viewModel: Model
@State var showDetail = false
@State var selectedListener: UserProfile? = nil

var body: some View {
    ScrollView {
        VStack(spacing:20) {
            ForEach(viewModel.allActiveListeners) { listener in
                UserImageSection(listener: listener,
                                 subtext: listener.supportAreas)
                    .onTapGesture(perform: {
                        handleTap(listener)
                    })
            }
        }
        
    }
    .padding(.horizontal,20)
    .sheet(isPresented: $showDetail, content: {
        if let listener = selectedListener {
            ListenerDetailView(listener: listener)
        }
        else {
            // It should never come here but when the first item is selected it does. The only way to not come here is to select another item after the first item has been selected.
            Text("Listener not loaded yet")
        }
    })
    
    
}

private func handleTap(_ listener: UserProfile) {
    print("Showing listener \(listener.id)")
    self.selectedListener = listener
    showDetail = true
    
}

}


Solution

  • In iOS 14, in order to get the .sheet to be presented with up-to-date data, you must use sheet(item:) instead of .sheet(isPresented:)

    You can see another one of my answers here: https://stackoverflow.com/a/66190152/560942 and SwiftUI: Switch .sheet on enum, does not work

    In your specific case, it's hard to tell since I don't have your UserProfile code, but I suggest that you:

    1. Get rid of your showDetail state variable
    2. Make sure that UserProfile conforms to Identifiable
    3. Change your sheet(isPresented:) to:
    .sheet(item: $selectedListener) { listener in 
      ListenerDetailView(listener: listener)
    }