Строки List сбрасывают состояние после переупорядочивания, потому что id — это индекс массива
Каждая строка хранит собственное @State (переключатель раскрыто/свёрнуто). После того как пользователь переупорядочит items, раскрытыми выглядят не те строки. Строки опознаются по индексу массива.
Требования:
- Объясните, почему после перемещения состояние привязывается не к той строке.
- Исправьте идентичность так, чтобы состояние строки следовало за её элементом данных, а не за слотом.
struct RowsView: View {
@State private var items: [String] = ["A", "B", "C"]
var body: some View {
List {
ForEach(Array(items.enumerated()), id: \.offset) { _, item in
RowView(title: item) // у RowView своё @State isExpanded
}
.onMove { from, to in items.move(fromOffsets: from, toOffset: to) }
}
}
}
Найдите и исправьте ошибку.
Привязка строк к индексу массива связывает идентичность с позицией: после переупорядочивания слот 0 остаётся тем же представлением со старым состоянием. Дайте элементу стабильный Identifiable id, чтобы идентичность шла за данными, а не за слотом.
- ✗Используют индекс массива (смещение) как идентичность строки
- ✗Считают, что SwiftUI отслеживает строки по содержимому, а не по заданному
id - ✗Добавляют
.id(UUID()), чтобы форсировать пересборку, вместо стабильной идентичности
- →В чём разница между структурной идентичностью и явной идентичностью через
.id()? - →Почему стабильный
Identifiableid сохраняет@Stateстроки при перемещении?
The rows are identified by id: \.offset — the array index. Identity is therefore the position, so after a move SwiftUI still sees "row 0, row 1, row 2" and keeps each slot's existing view (and its @State) while feeding it the reordered data. Structural identity (the index) no longer matches the data.
Fix it by giving each element a stable identity that travels with the data:
struct Item: Identifiable {
let id = UUID()
var title: String
}
struct RowsView: View {
@State private var items: [Item] = [Item(title: "A"), Item(title: "B"), Item(title: "C")]
var body: some View {
List {
ForEach(items) { item in // uses Item.id — stable per element
RowView(title: item.title)
}
.onMove { from, to in items.move(fromOffsets: from, toOffset: to) }
}
}
}
Now identity is Item.id, which moves with the element, so each row's @State follows its data through the reorder. This is the difference between structural identity (position in the tree) and explicit identity (a stable value you supply).