I have a list that displays a CoreData FetchRequest, and I have a Picker that changes how the list is sorted. The current way I implemented this looks like:
struct ParentView: View {
enum SortMethod: String, CaseIterable, Identifiable {
var id: Self { self }
case byName = "Name"
case byDateAdded = "Date Added"
}
@State private var currentSortMethod = SortMethod.byName
var body: some View {
ItemListView(sortMethod: currentSortMethod) // See child view implementation below
.toolbar {
ToolbarItem(placement: .principal) {
Picker("Sort by", selection: $currentSortMethod) {
ForEach(SortMethod.allCases) { sortMethod in
Text(sortMethod.rawValue)
}
}
}
}
}
}
and the child view looks like:
struct ItemListView: View {
@Environment(\.managedObjectContext) private var managedObjectContext
@FetchRequest var items: FetchedResults<Item>
init(sortMethod: ParentView.SortMethod) {
let sortDescriptor: NSSortDescriptor
switch sortMethod {
case .byName:
sortDescriptor = NSSortDescriptor(keyPath: \Item.name, ascending: true)
case .byDateAdded:
sortDescriptor = NSSortDescriptor(keyPath: \Item.dateAdded, ascending: true)
}
_items = .init(
entity: Item.entity(),
sortDescriptors: [sortDescriptor],
predicate: nil,
animation: .default
)
}
var body: some View {
List {
ForEach(items) { item in
SingleItemView(item)
}
}
}
}
However, when I change the sorting option, the list doesn't animate the reordering (presumably due to the entire ItemListView
being reconstructed. If I add .animation(.default)
to ItemListView()
in the parent view, the list animates when reordering, but also has weird animations when navigating back from other views. I can't seem to figure out where I might be able to add a withAnimation { }
block. Or is there a better approach to this that's more natural to SwiftUI and thus allows some default animation?