这里有另一种选项,使用新的 Realm frozen() 集合。虽然现在还处于早期阶段,但当“资产”被添加到数据库中时,UI 会自动更新。在本例中,它们是从 NSOperation 线程中添加的,应该是一个后台线程。
在此示例中,侧边栏列出基于数据库中不同值的不同属性组 - 请注意,您可能希望以更健壮的方式实现此功能 - 但作为一个快速 POC,这很好用。请参见下面的图像。
struct CategoryBrowserView: View {
@ObservedObject var assets: RealmSwift.List<Asset> = FileController.shared.assets
@ObservedObject var model = ModelController.shared
@State private var searchTerm: String = ""
@State var isEventsShowing: Bool = false
@State var isProjectsShowing: Bool = false
@State var isLocationsShowing: Bool = false
var projects: Results<Asset> {
return assets.sorted(byKeyPath: "project").distinct(by: ["project"])
}
var events: Results<Asset> {
return assets.sorted(byKeyPath: "event").distinct(by: ["event"])
}
var locations: Results<Asset> {
return assets.sorted(byKeyPath: "location").distinct(by: ["location"])
}
@State var status: Bool = false
var body: some View {
VStack(alignment: .leading) {
ScrollView {
VStack(alignment: .leading) {
DisclosureGroup(isExpanded: $isProjectsShowing) {
VStack(alignment:.trailing, spacing: 4) {
ForEach(filteredProjectsCollection().freeze()) { asset in
HStack {
Text(asset.project)
Spacer()
Image(systemName: self.model.selectedProjects.contains(asset.project) ? "checkmark.square" : "square")
.resizable()
.frame(width: 17, height: 17)
.onTapGesture { self.model.addProject(project: asset.project) }
}
}
}.frame(maxWidth:.infinity)
.padding(.leading, 20)
} label: {
HStack(alignment:.center) {
Image(systemName: "person.2")
Text("Projects").font(.system(.title3))
Spacer()
}.padding([.top, .bottom], 8).foregroundColor(.secondary)
}
DisclosureGroup(isExpanded: $isEventsShowing) {
VStack(alignment:.trailing, spacing: 4) {
ForEach(filteredEventsCollection().freeze()) { asset in
HStack {
Text(asset.event)
Spacer()
Image(systemName: self.model.selectedEvents.contains(asset.event) ? "checkmark.square" : "square")
.resizable()
.frame(width: 17, height: 17)
.onTapGesture { self.model.addEvent(event: asset.event) }
}
}
}.frame(maxWidth:.infinity)
.padding(.leading, 20)
} label: {
HStack(alignment:.center) {
Image(systemName: "calendar")
Text("Events").font(.system(.title3))
Spacer()
}.padding([.top, .bottom], 8).foregroundColor(.secondary)
}
DisclosureGroup(isExpanded: $isLocationsShowing) {
VStack(alignment:.trailing, spacing: 4) {
ForEach(filteredLocationCollection().freeze()) { asset in
HStack {
Text(asset.location)
Spacer()
Image(systemName: self.model.selectedLocations.contains(asset.location) ? "checkmark.square" : "square")
.resizable()
.frame(width: 17, height: 17)
.onTapGesture { self.model.addLocation(location: asset.location) }
}
}
}.frame(maxWidth:.infinity)
.padding(.leading, 20)
} label: {
HStack(alignment:.center) {
Image(systemName: "flag")
Text("Locations").font(.system(.title3))
Spacer()
}.padding([.top, .bottom], 8).foregroundColor(.secondary)
}
}.padding(.all, 10)
.background(Color(NSColor.controlBackgroundColor))
}
SearchBar(text: self.$searchTerm)
.frame(height: 30, alignment: .leading)
}
}
func filteredProjectsCollection() -> AnyRealmCollection<Asset> {
if self.searchTerm.isEmpty {
return AnyRealmCollection(self.projects)
} else {
return AnyRealmCollection(self.projects.filter("project CONTAINS[c] %@ || event CONTAINS[c] %@ || location CONTAINS[c] %@ || tags CONTAINS[c] %@", searchTerm, searchTerm, searchTerm, searchTerm))
}
}
func filteredEventsCollection() -> AnyRealmCollection<Asset> {
if self.searchTerm.isEmpty {
return AnyRealmCollection(self.events)
} else {
return AnyRealmCollection(self.events.filter("project CONTAINS[c] %@ || event CONTAINS[c] %@ || location CONTAINS[c] %@ || tags CONTAINS[c] %@", searchTerm, searchTerm, searchTerm, searchTerm))
}
}
func filteredLocationCollection() -> AnyRealmCollection<Asset> {
if self.searchTerm.isEmpty {
return AnyRealmCollection(self.locations)
} else {
return AnyRealmCollection(self.locations.filter("project CONTAINS[c] %@ || event CONTAINS[c] %@ || location CONTAINS[c] %@ || tags CONTAINS[c] %@", searchTerm, searchTerm, searchTerm, searchTerm))
}
}
func filteredCollection() -> AnyRealmCollection<Asset> {
if self.searchTerm.isEmpty {
return AnyRealmCollection(self.assets)
} else {
return AnyRealmCollection(self.assets.filter("project CONTAINS[c] %@ || event CONTAINS[c] %@ || location CONTAINS[c] %@ || tags CONTAINS[c] %@", searchTerm, searchTerm, searchTerm, searchTerm))
}
}
func delete(at offsets: IndexSet) {
if let realm = assets.realm {
try! realm.write {
realm.delete(assets[offsets.first!])
}
} else {
assets.remove(at: offsets.first!)
}
}
}
struct CategoryBrowserView_Previews: PreviewProvider {
static var previews: some View {
CategoryBrowserView()
}
}
struct CheckboxToggleStyle: ToggleStyle {
func makeBody(configuration: Configuration) -> some View {
return HStack {
configuration.label
Spacer()
Image(systemName: configuration.isOn ? "checkmark.square" : "square")
.resizable()
.frame(width: 22, height: 22)
.onTapGesture { configuration.isOn.toggle() }
}
}
}
![enter image description here](https://istack.dev59.com/0XdxN.webp)