skip to Main Content

Here’s the code

import SwiftUI

struct MyView: View {

@State private var Items = ["Apple", "Microsoft", "Google"]
@State private var presentSheet = Bool()

    var body: some View {
        NavigationStack {
            List {
                ForEach(Items) { item in 
                    Text(item)
                        .swipeActions(edge: .leading) {
                            Button("Show", systemImage: "eye" {
                                presentSheet.toggle
                            }
                            .tint(Color.yellow)
                        }

                    .sheet(isPresented: $presentSheet) {
                        Text(item)
                    }
                }
            }
            .navigationTitle("MyView")
        }
    }
}

The sheet only shows the last item in the array, when it should show the item that opened the sheet

I know I’m stupid, but I’m currently learning SwiftUI, and I’ve done it for over a year now

I tried making a sheet view that only displays the text you selected

I was expecting it to show the single item, but instead just showed the last item in the array

2

Answers


  1. Instead of presentSheet, use selectedItem to use .sheet(item: $selectedItem). I added the @MainActor annotation for safety reasons, and you should use it, too. If you compile it with Swift 6, you will get a warning that you should use @retroactive (SE-0364) to conform String to Identifiable.

    extension String: Identifiable {
        public var id: Self { self }
    }
    
    @MainActor
    struct MyView: View {
        @State private var items = ["Apple", "Microsoft", "Google"]
        @State private var selectedItem: String? = nil
        
        var body: some View {
            NavigationStack {
                List(items, id: .self) { item in
                    Text(item)
                        .swipeActions(edge: .leading) {
                            Button("Show", systemImage: "eye") {
                                selectedItem = item
                            }
                            .tint(.yellow)
                        }
                }
                .navigationTitle("MyView")
                .sheet(item: $selectedItem) { string in
                    Text(string)
                }
            }
        }
    }
    
    Login or Signup to reply.
  2. Downvoted because your code contains too many compilation errors, but here’s how to go about it:

    import SwiftUI
    
    struct SheetItemView: View {
        
        @State private var items = ["Apple", "Microsoft", "Google"]
        @State private var presentSheet = false
        @State private var selectedItem: String = "" // <- Here, added a state to show the selected array item
        
        var body: some View {
            NavigationStack {
                List {
                    ForEach(items, id:.self) { item in
                        Text(item)
                            .swipeActions(edge: .leading) {
                                Button("Show", systemImage: "eye") {
                                    presentSheet = true
                                    selectedItem = item // <- Here, on button press, set the state to the respective array item
                                }
                                .tint(Color.yellow)
                            }
                            .sheet(isPresented: $presentSheet, onDismiss: {
                                selectedItem = "" // <- Here, when sheet is dismissed, clear the state
                            }) {
                                Text(selectedItem) // <- Here, display the text currently set in the state
                            }
                    }
                }
                .navigationTitle("MyView")
            }
        }
    }
    
    #Preview {
        SheetItemView()
    }
    

    The code as you had it couldn’t work, because the sheet doesn’t show the item at the time the ForEach loop runs. It shows some content at the time the button is pressed (or, whatever item was in the loop at the moment the modifier was attached).

    To fix it, have the button set a state with the value of the item and read the state when the sheet opens. To keep it clean, since in this case, the state is a non-optional string, clear the state when the sheet is dismissed.

    This will be easier to understand if the code is restructured to have the sheet modifier outside the loop, since there is no need for each array item to have its own sheet modifier if they all read from the same shared state value anyway:

    import SwiftUI
    
    struct SheetItemView: View {
        
        @State private var items = ["Apple", "Microsoft", "Google"]
        @State private var presentSheet = false
        @State private var selectedItem: String = ""
        
        var body: some View {
            NavigationStack {
                List {
                    ForEach(items, id:.self) { item in
                        Text(item)
                            .swipeActions(edge: .leading) {
                                Button("Show", systemImage: "eye") {
                                    presentSheet = true
                                    selectedItem = item
                                }
                                .tint(Color.yellow)
                            }
                    }
                }
                .navigationTitle("MyView")
                .sheet(isPresented: $presentSheet, onDismiss: { // <- Here, moved sheet outside of the loop
                    selectedItem = ""
                }) {
                    Text(selectedItem)
                }
            }
        }
    }
    
    #Preview {
        SheetItemView()
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search