Why this title?
Because List, ForEach and CoreData are the three major culprits in my opinion...well, if not simply .transition() itself.
What I want
Basically I want, say, a list of tasks stored in the Core Data, and on tapping a task, it just disappears with .transition(.scale). Several potential solutions that I have tried all failed both in the canvas and the simulators, two of which are on the stack overflow:
- SwiftUI insertion transion is not working when view added
- Transition animation not working in SwiftUI
And the rest of attempts are just inserting the .transition(.scale) in all plausible places, and with/without .animation(...) attached.
An overview of code
Here is the basic structure of my buggy view:
struct DeadlineListView: View {
@FetchRequest(entity: Deadline.entity(),
sortDescriptors: [NSSortDescriptor(keyPath: \Deadline.dueTime, ascending: true)],
predicate: NSPredicate(format: "isCompleted == false"),
animation: Animation.linear(duration: 2)
) var deadlineList: FetchedResults<Deadline>
// some other vars...
var body: some View {
VStack(spacing: 0.0) {
HStack {
// some other views...
}
// --- Where things matter most ---
List {
ForEach(deadlineList, id: \.uid) { deadline in
Button(action: { isShowingDeadlineDetails = true }) {
DeadlineView(deadline: deadline)
}.sheet(isPresented: $isShowingDeadlineDetails) {
DeadlineDetailView(deadline: deadline)
}
.listRowInsets(EdgeInsets())
}
}
// --- Where things matter most ---
}
}
}
So technically I have a list of Buttons, which look like DeadlineView(...).
DeadlineView(...) has a button for the user to tap on to signal that a task is completed:
Button(action: {
deadline.isCompleted = true
deadline.objectWillChange.send()
do {
try context.save()
} catch {
print("Unable to save deadline isCompleted in DeadlineView!")
}
}){
// some View...
}
This button will make the NSPredicate ignore this task, and thus the task disappears from my list.
What I actually get
Yes, it does do the animation. But the completed task is squeezed up by the task right below it without any visible(at least to me) .transition(.scale).
Where I have placed .transition(.scale)
Back to the first snippet:
List {
ForEach(deadlineList, id: \.uid) { deadline in
Button(action: { isShowingDeadlineDetails = true }) {
DeadlineView(deadline: deadline)
// .transition(.scale) 1. HERE!
}
// 2. HERE!
.sheet(isPresented: $isShowingDeadlineDetails) {
DeadlineDetailView(deadline: deadline)
}
// 3. HERE!
.listRowInsets(EdgeInsets())
// 4. HERE!
}
// 5. HERE!
}
// 6. HERE!
All with/without .animation(.linear(duration: 2)) attached behind.
Just another minor discovery
As you might have noticed, the duration for the animation(2) is pretty long so that it goes slowly enough for me to observe that it is not transitioning indeed.
But interestingly, it does not respond to that duration, be it 0.2 or 2(Well, at least for me it does not seem to last for 2 seconds).
Any solutions or workarounds are welcomed.
Since transition affect many view here. You have to do the changes related to transition inside
This link may helpfull https://www.youtube.com/watch?v=3krC2c56ceQ