'Sheet inside ForEach doesn't loop over items SwiftUI
I have an issue using a sheet inside a ForEach. Basically I have a List that shows many items in my array and an image that trigger the sheet. The problem is that when my sheet is presented it only shows the first item of my array which is "Harry Potter" in this case.
Here's the code
struct ContentView: View {
@State private var showingSheet = false
var movies = ["Harry potter", "Mad Max", "Oblivion", "Memento"]
var body: some View {
NavigationView {
List {
ForEach(0 ..< movies.count) { movie in
HStack {
Text(self.movies[movie])
Image(systemName: "heart")
}
.onTapGesture {
self.showingSheet = true
}
.sheet(isPresented: self.$showingSheet) {
Text(self.movies[movie])
}
}
}
}
}
}
Solution 1:[1]
There should be only one sheet, so here is possible approach - use another sheet modifier and activate it by selection
Tested with Xcode 12 / iOS 14 (iOS 13 compatible)
extension Int: Identifiable {
public var id: Int { self }
}
struct ContentView: View {
@State private var selectedMovie: Int? = nil
var movies = ["Harry potter", "Mad Max", "Oblivion", "Memento"]
var body: some View {
NavigationView {
List {
ForEach(0 ..< movies.count) { movie in
HStack {
Text(self.movies[movie])
Image(systemName: "heart")
}
.onTapGesture {
self.selectedMovie = movie
}
}
}
.sheet(item: self.$selectedMovie) {
Text(self.movies[$0])
}
}
}
}
Solution 2:[2]
I changed your code to have only one sheet and have the selected movie in one variable.
extension String: Identifiable {
public var id: String { self }
}
struct ContentView: View {
@State private var selectedMovie: String? = nil
var movies = ["Harry potter", "Mad Max", "Oblivion", "Memento"]
var body: some View {
NavigationView {
List {
ForEach(movies) { movie in
HStack {
Text(movie)
Image(systemName: "heart")
}
.onTapGesture {
self.selectedMovie = movie
}
}
}
.sheet(item: self.$selectedMovie, content: { selectedMovie in
Text(selectedMovie)
})
}
}
}
Solution 3:[3]
Wanted to give my 2 cents on the matter. I was encountering the same problem and Asperi's solution worked for me. BUT - I also wanted to have a button on the sheet that dismisses the modal.
When you call a sheet
with isPresented
you pass a binding Bool and so you change it to false
in order to dismiss.
What I did in the item
case is I passed the item as a Binding. And in the sheet, I change that binding item to nil
and that dismissed the sheet.
So for example in this case the code would be:
var movies = ["Harry potter", "Mad Max", "Oblivion", "Memento"]
var body: some View {
NavigationView {
List {
ForEach(0 ..< movies.count) { movie in
HStack {
Text(self.movies[movie])
Image(systemName: "heart")
}
.onTapGesture {
self.selectedMovie = movie
}
}
}
.sheet(item: self.$selectedMovie) {
Text(self.movies[$0])
// My addition here: a "Done" button that dismisses the sheet
Button {
selectedMovie = nil
} label: {
Text("Done")
}
}
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | Dharman |
Solution 3 | Rutang |