@ State - это свойство-обертка, которое заставит View, в котором он определен, пересчитать его тело.
В вашем случае, если вы удалите элемент по индексу,
HStack {
Text("\(index)")
Spacer()
Text("\(self.list[index].name)")
}
.background(Color.gray.opacity(0.001))
.onTapGesture {
self.list.remove(at: index)
}
Текст внутри HStack
Text("\(self.list[index].name)")
cra sh, просто потому что список [index] больше не существует.
Использование
ForEach(list.indices, id:\.self) { index in ... }
вместо
ForEach(list.indices) { index in ... }
заставит SwiftUI воссоздать TestView (см. Id: \. Self в конструкторе ForEach)
SwiftUI сделает fre sh копию TestView при использовании значения fre sh имущества, завернутого в обертку свойства @State.
ОБНОВЛЕНИЕ
Пожалуйста, не обновляйте свой вопрос ...
Ваша последняя версия кода 4 - полная путаница, поэтому я переписал ее на то, что вы можете скопировать - вставить - запустить
import SwiftUI
struct Name: Identifiable, Hashable {
var id: String = UUID().uuidString
var name: String
var marked: Bool
init(_ name: String, marked: Bool = false) { self.name = name; self.marked = marked }
}
struct ContentView: View {
@State private var list: [Name] = [Name("test1"), Name("test2"), Name("test3", marked: true), Name("test4"), Name("test5", marked: true), Name("test6"), Name("test7"), Name("test8")]
@State private var showMarkedOnly = false
var body: some View {
VStack{
Toggle(isOn: $showMarkedOnly) {
Text("show marked only")
}.padding(.horizontal)
List {
ForEach(Array(zip(0..., list)).filter({!self.showMarkedOnly || $0.1.marked}), id: \.1.id) { index, name in
HStack {
Text("\(index)").foregroundColor(name.marked ? .red : .gray)
Spacer()
Text("\(name.name)")
}
.background(Color.gray.opacity(0.001))
.onTapGesture {
self.list.remove(at: index)
}
}
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
она должна выглядеть как
ОБНОВЛЕНИЕ, основанное на обсуждении
ForEach разные версии конструкторов используют внутренне различную функциональность ViewBuilder
@available(iOS 13.0, OSX 10.15, tvOS 13.0, watchOS 6.0, *)
extension ViewBuilder {
/// Provides support for "if" statements in multi-statement closures, producing an `Optional` view
/// that is visible only when the `if` condition evaluates `true`.
public static func buildIf<Content>(_ content: Content?) -> Content? where Content : View
/// Provides support for "if" statements in multi-statement closures, producing
/// ConditionalContent for the "then" branch.
public static func buildEither<TrueContent, FalseContent>(first: TrueContent) -> _ConditionalContent<TrueContent, FalseContent> where TrueContent : View, FalseContent : View
/// Provides support for "if-else" statements in multi-statement closures, producing
/// ConditionalContent for the "else" branch.
public static func buildEither<TrueContent, FalseContent>(second: FalseContent) -> _ConditionalContent<TrueContent, FalseContent> where TrueContent : View, FalseContent : View
}
Речь идет о «деталях реализации», и, надеюсь, это будет документировано в следующем выпуске. SwiftUI все еще находится на очень ранней стадии разработки, мы должны быть осторожны.
Давайте попробуем заставить SwiftUI идти своим путем! Первый отдельный RowView
struct RowView: View {
var showMarkedOnly: Bool
var index: Int
var name: Name
//@ViewBuilder
var body: some View {
if !self.showMarkedOnly || name.marked {
HStack {
Text(verbatim: index.description).foregroundColor(name.marked ? .red : .gray)
Spacer()
Text(verbatim: name.name)
}
.background(Color.gray.opacity(0.001))
}
}
}
Компилятор жалуется на
Function declares an opaque return type, but has no return statements in its body from which to infer an underlying type
Раскомментируйте строку, чтобы обернуть наше тело
struct RowView: View {
var showMarkedOnly: Bool
var index: Int
var name: Name
@ViewBuilder
var body: some View {
if !self.showMarkedOnly || name.marked {
HStack {
Text(verbatim: index.description).foregroundColor(name.marked ? .red : .gray)
Spacer()
Text(verbatim: name.name)
}
.background(Color.gray.opacity(0.001))
}
}
}
Теперь мы можем использовать код так, как вам нравится : -)
struct ContentView: View {
@State private var list: [Name] = [Name("test1"), Name("test2"), Name("test3", marked: true), Name("test4"), Name("test5", marked: true), Name("test6"), Name("test7"), Name("test8")]
@State private var showMarkedOnly = false
var body: some View {
VStack{
Toggle(isOn: $showMarkedOnly) {
Text("show marked only")
}.padding(.horizontal)
List {
ForEach(Array(zip(0..., list)), id: \.1.id) { (index, name) in
RowView(showMarkedOnly: self.showMarkedOnly, index: index, name: name).onTapGesture {
self.list.remove(at: index)
}
}
}
}
}
}
В конечном результате теперь используется конструкция buildIf<Content>
, и весь код снова работает (результат выглядит точно так же, как показано выше)