I am trying to implement a SwiftUI list for a sidebar view which has at least 3 different types of data points: a) a fixed list of enums, b) a list of 'tags' coming from a @FetchRequest using Core Data, c) a similar list of 'groups' coming from a different @FetchRequest.
I'm struggling with how to handle multiple selection with List
in this setup. The user should be able to select from different sections (and I get change notifications to fine-tune the handling). I have tried making the 'selection' type to be UUID, and setting the id for each leaf view explicitly, but it doesn't seem to work (I don't the selection highlight).
This is the list I made:
struct CombinedListView: View {
@FetchRequest(
entity: CJTag.entity(),
sortDescriptors: [NSSortDescriptor(keyPath: \CJTag.displayOrder, ascending: true)]
)
var tags: FetchedResults<CJTag>
@FetchRequest(
entity: PrivateGroups.entity(),
sortDescriptors: [NSSortDescriptor(keyPath: \PrivateGroups.displayOrder, ascending: true)]
)
var groups: FetchedResults<PrivateGroups>
@State private var selectedItems = Set<UUID>()
var body: some View {
NavigationView {
VStack {
List(selection: $selectedItems) {
// section for Tabs
Section(header: Text("Main Tabs")) {
ForEach(MainTab.allCases, id: \.rawValue) { tab in
Text(tab.rawValue)
.id(tab.id)
}
}
// Section for Tags
if !tags.isEmpty {
Section(header: Text("Tags")) {
ForEach(tags) { tag in
Text(tag.tagName ?? "Tag")
.id(tag.objectID.uriRepresentation().absoluteString) // Directly tag with UUID
.contentShape(Rectangle())
}
}
}
// Section for Groups
if !groups.isEmpty {
Section(header: Text("Groups")) {
ForEach(groups) { group in
Text(group.groupName ?? "Group")
.id(group.objectID.uriRepresentation().absoluteString)
.contentShape(Rectangle())
}
}
}
}
.listStyle(SidebarListStyle())
.navigationTitle("Selectable List")
}
}
}
}
I know that if I just had NSManagedObjects
in the list, I could set the 'selection' type to be NSManagedObjectID
and it would work. But I needed it to support a list of enum cases as well.
I tried setting the tag
for each row view as well (using the same stuff as id
modifier), but that doesn't work either. I'm sure it's a case of mismatched 'types' for selection, but I can't figure out the best setup to accomplish this.
EDIT:
Added code for MainTab:
// Enum for Main Tabs
enum MainTab: String, CaseIterable, Identifiable {
case home = "Home"
case favorites = "Favorites"
case settings = "Settings"
case profile = "Profile"
case help = "Help"
var id: String { rawValue }
var iconName: String { rawValue.lowercased() }
}
The selections do not work because you have different types for your
@State private var selectedItems = Set<UUID>()
and the .id(...)
which are Strings. They must be of the same type to work.
So change your selection to match
@State private var selectedItems = Set<String>()
and I recommend using .tag(...)
instead of .id(...)
.
And as I mentioned in my comment, NavigationView
is deprecated use NavigationStack
instead.