This gist demonstrates a bug in SwiftUI.List animated updates when quickly applying changes. Run the gist and then tap "Move" and "Back" in quick succession. The list will be put into strange states where section titles show in rows and row titles show in section headers.
Created
February 10, 2021 17:20
-
-
Save crayment/f045c07a7d2648492d6ae8831cc5b573 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import SwiftUI | |
struct ListAnimationsView: View { | |
struct Item: Identifiable { | |
var name: String | |
var id: String { name } | |
static var currentID = 0 | |
static func new() -> Item { | |
currentID += 1 | |
return .init(name: "Row \(currentID)") | |
} | |
} | |
struct Section: Identifiable { | |
var name: String | |
var items: [Item] | |
var id: String { | |
name | |
} | |
} | |
@State var sections: [Section] = [ | |
Section(name: "Section 1", items: [.new(), .new()]), | |
Section(name: "Section 2", items: [.new(), .new()]), | |
] | |
var body: some View { | |
NavigationView { | |
VStack { | |
HStack { | |
Button(action: { | |
sections[0].items.append(Item.new()) | |
}, label: { | |
Text("Add S1") | |
}) | |
Button(action: { | |
guard !sections[0].items.isEmpty else { return } | |
sections[1].items.append(sections[0].items.removeLast()) | |
}, label: { | |
Text("Move") | |
}) | |
Button(action: { | |
guard !sections[1].items.isEmpty else { return } | |
sections[0].items.append(sections[1].items.removeLast()) | |
}, label: { | |
Text("Back") | |
}) | |
} | |
List { | |
ForEach(sections, id: \.id) { section in | |
SwiftUI.Section(header: Text(section.name)) { | |
ForEach(section.items, id: \.id) { item in | |
Text(item.name) | |
} | |
.onDelete(perform: { indexSet in | |
delete(sectionID: section.id, indexSet: indexSet) | |
}) | |
} | |
.id(section.id) | |
} | |
} | |
.listStyle(GroupedListStyle()) | |
.animation(.default) | |
} | |
} | |
.navigationBarItems(trailing: trailingNavItems) | |
} | |
var trailingNavItems: some View { | |
HStack { | |
Button(action: {}, label: { | |
Image(systemName: "note.text") | |
}) | |
Spacer(minLength: 20) | |
Button(action: {}, label: { | |
Image(systemName: "folder.fill") | |
}) | |
} | |
} | |
func delete(sectionID: String, indexSet: IndexSet) { | |
guard | |
let sectionIndex = sections.firstIndex(where: { $0.id == sectionID }) | |
else { | |
return | |
} | |
sections[sectionIndex].items.remove(atOffsets: indexSet) | |
} | |
} | |
struct ListAnimationsView_Previews: PreviewProvider { | |
static var previews: some View { | |
ListAnimationsView() | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment