Reputation: 16735
I have an array of objects that I'm able to render in a SwiftUI view. It's very simple to display them as a List, however I'd like to create sections and group by one of the elements' properties.
I tried up using Dictionary(grouping:by:)
and then sorting by the dictionary's keys to get the sections, however this slows the UI down. It feels like I'm doing something wrong.
List {
ForEach(myArray.keys.sorted(), id: \.self) { mySection in
Section(header: Text(mySection)) {
ForEach(myArray[mySection] ?? []) { element in
NavigationLink {
DetailView(element: element)
} label: {
ElementRow(element: element)
}
}
}
}
}
Is there a more efficient way than Dictionary(grouping:by:)
to group data retrieved from SwiftData into sections?
Upvotes: 3
Views: 2579
Reputation: 16735
I found a framework on GitHub called SectionedQuery which does exactly what I need it to:
@State private var searchTerm = ""
@SectionedQuery(sectionIdentifier: \MyObject.id ,
sortDescriptors: [
SortDescriptor(\MyObject.property1),
SortDescriptor(\ MyObject.property2)
],
animation: .smooth
)
var sections
// stuff
List {
// my list consuming sections
}
.searchable(text: $searchTerm)
To use it with a predicate, I did the following:
List {
// list code
}
.searchable(text: $searchTerm)
.onChange(of: searchTerm) {
togglePredicate()
}
func togglePredicate() {
guard !searchTerm.isEmpty else {
sections.predicate = nil
return
}
sections.predicate = #Predicate<MyThing> {
$0.someProperty.localizedStandardContains(searchTerm)
}
}
Upvotes: 1
Reputation: 30746
Instead of List
try OutlineGroup
for your grouped data.
You might need to transform your data into groups which you can do in a computed property in the parent View
's body where you init the View
that contains the OutlineGroup
.
Upvotes: 0