SwiftUI: Персонализированный sheet для разных строк в List

swift
swiftui

#1

Добрый день. Я вывожу список с помощью List и ForEach. Мне надо, что бы по нажатию на любую строку этого списка вызывался sheet с данными из этой строки. Пробую делать так:

@State private var showSheet = false
var body: some View {
    List {
        ForEach(self.exp, id: \.self.id) { exp in
            VStack {
                Text(exp.text1)
                Text(exp.text2)
            }
             .onTapGesture {
                 self.showSheet = true
            }
             .sheet(isPresented: self.$showSheet) {
                 SomeView(exp)
            }
        }   
    }
}

self.exp получаю из CoreData

И вроде при касании по строке sheet вызывается, но вызывается как будто бы коснулись первую строку, хотя по факту касание может быть и по пятой строке. Я так понимаю, что при касании даже по пятой строке, showSheet становится True и вызывается первый sheet который ждет это условие. А это именно sheet для первой строки.

Так вот как из .onTapGesture передать параметр в .sheet, что бы именно с этим параметром вызывался SomeView?


#2
  1. Попробуйте в вашу модель exp добавить параметр var id: UUID?. Ячейки переиспользуются и неплохо иметь уникальный идентификатор для каждой, чтобы список знал, на какую ячейку идёт тап.
    Ещё вариант такой может помочь.

    List {
        ...
    }.UUID()
    

Но лучше в модель добавить id.

  1. Sheet должен быть прикреплён к верхнему вью, а не внутри списка! То есть после List.

  2. Вместо View+TapGesture, мне кажется, лучше использовать Button :slight_smile:


#3

У exp есть id. Как мне в .sheet понимать по какой ячейке был тап? Или хотя бы id этот в .sheet как передать?

Идея с Button интересная. Попробую в этом направлении поковырять.


#4

Пробую все-таки пока через тап. Немного изменил код. Теперь SomeView просит в параметр id записи. Потом по этом id достаю саму запись, тут вопросов нет. Вопрос в том, как же этот id получить?

@State private var showSheet = false
var body: some View {
    List {
        ForEach(self.exp, id: \.self.id) { exp in
            VStack {
                Text(exp.text1)
                Text(exp.text2)
            }.onTapGesture {
                 self.showSheet = true }
        }
    }.sheet(isPresented: self.$showSheet) {
         SomeView(id) // как получить id? 
        }   
}

#5

Пишите id в любую переменную при тапе , её передавайте в sheet.