I can't for the life of me get transitions and animations to work well with SwiftData and List on MacOS 15 and iOS 18.
I've included an example below, where I define several animations and a transition type, but they are all ignored.
How do I animate items being added to / removed from a List()?
I am attached to List() due to its support for selection, context menu, keyboard shortcuts, etc. If I would switch to ScrollView with VStack I would have to rebuild all of that.
Also, this is super basic and should just work, right?
Thanks for reading.
import SwiftUI
import SwiftData
struct ContentView: View {
@Environment(\.modelContext) private var modelContext
/// Issues on iOS:
/// Items animate into and out of view, but I seem to have no control over the animation.
/// In the code here I've specified a 'bouncy' and a slow 'easeIn' animation: both are not triggered.
/// The code also specifies using a 'slide' transition, but it is ignored.
/// -> How do I control the transition and animation timing on iOS?
///
/// Issues on MacOS:
/// Items do not animate at all on MacOS! They instantly appear and are instantly removed.
/// -> How do I control the transition and animation timing on MacOS?
// animation added here -> has no effect?
@Query(animation: .bouncy) private var items: [Item]
var body: some View {
VStack {
Button("Add to list") {
// called without 'withAnimation' -> no animation
let newItem = Item(timestamp: Date())
modelContext.insert(newItem)
}
List() {
ForEach(items, id: \.self) { item in
Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))
.transition(.slide) // items do not slide in/out of view
.onTapGesture {
// called with 'withAnimation' -> no animation
withAnimation(.easeIn(duration: 2)) {
modelContext.delete(item)
}
}
}
.animation(.spring(duration: 3), value: items)
}
}
.padding()
}
}
#Preview {
ContentView()
.modelContainer(for: Item.self, inMemory: true)
}
The issue is triggered because of the use of SwiftUI List – If you simply comment out the list in your code, as shown below, the animation will work:
//List() {
ForEach(items, id: \.self) { item in
Text(item.timestamp, format: Date.FormatStyle(date: .numeric, time: .standard))
.transition(.slide) // items do not slide in/out of view
.onTapGesture {
// called with 'withAnimation' -> no animation
withAnimation(.easeIn(duration: 2)) {
modelContext.delete(item)
}
}
}
.animation(.spring(duration: 3), value: items)
//}
SwiftUI List is supposed to automatically manage the animation of its items when they are inserted or deleted. I don’t see a good way that allows you to use SwiftUI List with your own animation. If that is important to your app, you might consider filing a feedback report (http://developer.apple.com/bug-reporting/) for SwiftUI folks to investigate – If you do so, please share your report ID for folks to track.
Best,
——
Ziqiao Chen
Worldwide Developer Relations.