I have a view where I need to shuffle/sort the content shown in a ForEach 'list'.
When manipulating the array, the animation is somehow everything else but seamless. The animation fails in 8 out of 10 cases and I don't understand why.
I've included a simplified version of my code with the same odd behaviour and a screen recording below.
Am I missing something or is this a swiftUI bug?
struct TestView: View {
@State private var array: [Element] = [
Element(txt: "A"),
Element(txt: "B"),
Element(txt: "C"),
Element(txt: "D"),
Element(txt: "E"),
Element(txt: "F"),
Element(txt: "G"),
]
var body: some View {
VStack {
Text(verbatim: "Shuffle Animation")
.font(.title2)
.padding(.bottom, 50)
ForEach(array) { element in
VStack {
Text(verbatim: element.txt)
.padding()
}
.foregroundColor(.white)
.frame(maxWidth: .infinity)
.background(.orange)
.cornerRadius(8)
.contextMenu {
Button("shuffle", action: {
withAnimation {
array.shuffle()
}
})
}
}
.padding(.horizontal)
}
}
}
struct Element: Identifiable, Hashable {
var id: UUID = UUID()
var txt: String
}
Screen recording:
CodePudding user response:
Two things:
- Swift does fail to animate buttons that are being interacted with. You can work around this by using
DispatchQueue.main.asyncAfter
to introduce a slight delay before animating the shuffle. - Add an
id
inForEach
so that each letter animates from its old location to its new location.
ForEach(array, id: \.self) { element in
VStack {
Text(verbatim: element.txt)
.padding()
}
.foregroundColor(.white)
.frame(maxWidth: .infinity)
.background(.orange)
.cornerRadius(8)
.contextMenu {
Button("shuffle", action: {
DispatchQueue.main.asyncAfter(deadline: .now() 0.3) {
withAnimation {
array.shuffle()
}
}
})
}
}
.padding(.horizontal)