Transition is not working with ForEach nested in List with data from Core Data

378 views Asked by At

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:

  1. SwiftUI insertion transion is not working when view added
  2. 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.

1

There are 1 answers

1
YodagamaHeshan On

Since transition affect many view here. You have to do the changes related to transition inside

withAnimation(Animation.easeIn) { //here you can change the animation you want
               //state changes should write here
            }

This link may helpfull https://www.youtube.com/watch?v=3krC2c56ceQ