ios – No animation in subview using NavigationStack in SwiftUI


I have a problem with animations not working when my view is seen from its parent using NavigationStack. I have 2 simple views, parent:

struct ListEntitiesView: View {
    @Environment(\.managedObjectContext)
    private var viewContext
    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \ListEntity.name, ascending: true)],
        animation: .default
    )
    private var lists: FetchedResults<ListEntity>
    @State private var path = NavigationPath()

    var body: some View {
        NavigationStack(path: $path.animation()) {
            List {
                ForEach(lists) { list in
                    NavigationLink(value: list) {
                        ListEntityTile(list)
                    }
                }
            }
            .navigationTitle("ListEntities")
            .navigationBarTitleDisplayMode(.inline)
            .toolbar {
                Button {
                    let list = ListEntity(context: viewContext)
                    list.name = "List \(lists.count + 1)"
                    viewContext.forceSave()
                } label: {
                    Label("Add List", systemImage: "plus")
                }
            }
            .navigationDestination(for: ListEntity.self) { list in
                ListEntityView(list)
            }
        }
    }
}

and child:

struct ListEntityView: View {
    @Environment(\.managedObjectContext)
    private var viewContext
    @ObservedObject
    private var list: ListEntity
    @FetchRequest
    private var items: FetchedResults<ListItemEntity>

    init(_ list: ListEntity) {
        _list = ObservedObject(wrappedValue: list)
        _items = FetchRequest(
            fetchRequest: ListItemEntity.fetchRequest(
                of: list,
                sortDescriptors: [NSSortDescriptor(keyPath: \ListItemEntity.name?.name, ascending: true)]
            ),
            animation: .default
        )
    }

    var body: some View {
        List {
            ForEach(items) { item in
                ListItemTile(item)
            }
        }
        .navigationTitle(list.wrappedName)
        .navigationBarTitleDisplayMode(.inline)
        .toolbar {
            NavigationLink {
                AddListItemEntity(list)
            } label: {
                Label("Add Item", systemImage: "plus")
            }
        }
    }
}

struct ListItemTile: View {
    @Environment(\.managedObjectContext)
    private var viewContext
    @ObservedObject
    private var item: ListItemEntity

    init(_ item: ListItemEntity) {
        _item = ObservedObject(wrappedValue: item)
    }

    var body: some View {
        Button {
            item.flag.toggle()
            viewContext.forceSave()
        } label: {
            Label(item.wrappedName, systemImage: item.flag ? "checkmark.circle" : "circle")
        }
    }
}

In the child Preview, if I create it inside NavigationStack everything animates as expected:

#Preview {
    let list = ListEntity(context: DataProvider.shared.viewContext)
    list.name = "List"
    let name = NameEntity(context: DataProvider.shared.viewContext)
    name.name = "Name"
    let item = ListItemEntity(context: DataProvider.shared.viewContext)
    item.flag = false
    item.list = list
    item.name = name
    DataProvider.shared.viewContext.forceSave()
    return NavigationStack {
        ListEntityView(list)
            .environment(\.managedObjectContext, DataProvider.shared.viewContext)
    }
}

But once view is inside NavigationLink (or created in parent’s navigationDestination) nothing animates:

#Preview {
    let list = ListEntity(context: DataProvider.shared.viewContext)
    list.name = "List"
    let name = NameEntity(context: DataProvider.shared.viewContext)
    name.name = "Name"
    let item = ListItemEntity(context: DataProvider.shared.viewContext)
    item.flag = false
    item.list = list
    item.name = name
    DataProvider.shared.viewContext.forceSave()
    return NavigationStack {
        NavigationLink {
            ListEntityView(list)
        } label: {
            Text("List details")
        }
    }
    .environment(\.managedObjectContext, DataProvider.shared.viewContext)
}

I’ve found a thread on Apple’s developer forum, but solution from there doesn’t help in my case. Any other ideas? Or maybe my code have a bug in it I don’t see?

Latest articles

spot_imgspot_img

Related articles

Leave a reply

Please enter your comment!
Please enter your name here

spot_imgspot_img