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 Button
s, 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 transition
ing 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