我遇到一个问题,当我删除一个部分的最后一项时,标题都会短暂地向上移动。使用 Realm 在 SwiftUI 中处理这个问题有技巧吗?当一个项目不是一个部分的最后一行时,这不会发生。仅当该部分被删除时。
带有列表使用部分的选项卡。这是设置标题的地方。
struct HistoryTab: View {
@EnvironmentObject var realmManager: RealmManager
@EnvironmentObject var stateModel: StateModel
@Binding var showSideMenu: Bool
@Binding var showAddSheet: Bool
var toggleSideMenu: ((() -> ())?) -> ()
@State private var searchText = ""
var body: some View {
NavigationStack {
ZStack {
if realmManager.history?.count ?? 0 > 0 {
List {
ForEach(realmManager.groupedHistory.indices, id: \.self) { i in
if realmManager.groupedHistory[i].count > 0 {
Section {
let monthEntries = realmManager.groupedHistory[i]
HistoryRowsView(entries: monthEntries, index: i)
} header: {
Text(realmManager.groupedHistory[i].first?.monthYear ?? "")
}
}
}
}
.listStyle(.automatic)
} else {
VStack {
Spacer()
Text("Message")
.multilineTextAlignment(.center)
.font(Font.system(size: 18))
.foregroundColor(.secondary)
Spacer()
Spacer()
}
.frame(maxWidth: .infinity)
}
}
.allowsHitTesting(showSideMenu ? false : true)
.navigationTitle("History")
.navigationBarTitleDisplayMode(.large)
.toolbarBackground(stateModel.showNav, for: .navigationBar)
.toolbar(stateModel.showTab, for: .tabBar)
.toolbar {
ToolbarItem(placement: .navigationBarLeading) {
Button {
toggleSideMenu(nil)
} label: {
Image(systemName: "line.3.horizontal")
.font(.system(size: 18, weight: .regular))
}
}
ToolbarItem(placement: .navigationBarTrailing) {
Button {
withAnimation {
realmManager.addTestHistoryEntry()
}
} label: {
Image(systemName: "plus")
.font(.system(size: 18, weight: .medium))
.foregroundColor(Color("Burnt_Orange"))
}
}
}
.accentColor(Color("Burnt_Orange"))
.background {
Color.black.opacity(0.025)
}
.sheet(isPresented: $showAddSheet) {
showAddSheet = false
} content: {
EditEntrySheet(editType: .add)
.interactiveDismissDisabled()
}
}
}
}
每个部分的行视图以及如何删除项目。
struct HistoryRowsView: View {
@EnvironmentObject var realmManager: RealmManager
var index: Int
var body: some View {
if let array = realmManager.groupedHistory.getElement(at: index) {
ForEach(array) { entry in
if !entry.isInvalidated {
ZStack {
HistoryCell(entry: entry)
NavigationLink {
HistoryDetail(entry: entry)
} label: {
EmptyView()
}
.opacity(0.0)
}
}
}
.onDelete(perform: deleteEntry)
}
}
func deleteEntry(indexSet: IndexSet) {
guard let offset = indexSet.first else { return }
let entryRemove = realmManager.groupedHistory[index][offset]
delete(images: entryRemove.images)
if let entryDelete = realmManager.historyArray.first(where: { $0.id == entryRemove.id }) {
DispatchQueue.main.async {
realmManager.delete(entryDelete)
}
}
}
func delete(images: MutableSet<String>) {
for id in images {
ImageHandler.deleteImage(id: id)
}
}
}
具有观察者和历史条目分组的 RealmManager。
class RealmManager: ObservableObject {
private(set) var localRealm: Realm?
/// History entries
@Published var history: Results<HistoryEntry>?
@Published var historySearchFilter = ""
var historyArray: [HistoryEntry] {
if let history = history {
return Array(history)
} else {
return []
}
}
var groupedHistory: [[HistoryEntry]] {
if historySearchFilter.isEmpty {
return historyArray.group { $0.monthYear }
} else {
return historyArray.filter{ ($0.qualifier?.title.lowercased() ?? "").contains(historySearchFilter.lowercased()) }.group { $0.monthYear }
}
}
private var historyToken: NotificationToken?
init(name: String) {
initializeSchema(name: name)
setupHistoryObserver()
}
func initializeSchema(name: String) {
let docDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
let realmFileUrl = docDir.appendingPathComponent("\(name).realm")
let config = Realm.Configuration(fileURL: realmFileUrl, schemaVersion: 0) { migration, oldSchemaVersion in
}
Realm.Configuration.defaultConfiguration = config
do {
localRealm = try Realm()
} catch {
print("Error opening default realm", error)
}
}
func setupHistoryObserver() {
guard let realm = localRealm else { return }
let observedEntries = realm.objects(HistoryEntry.self).sorted(byKeyPath: "date", ascending: false)
historyToken = observedEntries({ [weak self] _ in
self?.history = observedEntries
})
}
}