如何为@ObservedResults实现标准的onMove方法?
实现ObservedResults列表的onMove功能推荐方案
要给基于ObservedResults的SwiftUI列表实现onMove功能,Realm并没有提供像Core Data那样的内置方法,标准做法是通过维护一个排序字段来手动管理列表顺序,具体步骤如下:
1. 给数据模型添加排序字段
首先需要在Item类中启用(或添加)一个用于标记顺序的字段,比如order:
class Item: Object, ObjectKeyIdentifiable { @Persisted(primaryKey: true) var _id: ObjectId @Persisted var name: String @Persisted var order: Int // 用于维护列表顺序的字段 }
2. 按排序字段查询数据
修改@ObservedResults的初始化,让它按order字段排序,确保列表显示的顺序与我们维护的顺序一致:
@ObservedResults(Item.self, sortDescriptor: SortDescriptor(keyPath: \Item.order)) var items
3. 实现onMove的核心逻辑
自定义moveItems方法,在Realm写事务中调整移动前后相关元素的order值:
private func moveItems(from source: IndexSet, to destination: Int) { let itemsArray = Array(items) // 在Realm写事务中修改数据 try? Realm().write { for oldIndex in source { let movedItem = itemsArray[oldIndex] if oldIndex < destination { // 向上移动:将中间元素的order减1,再设置被移动元素的order for i in oldIndex..<destination { itemsArray[i+1].order -= 1 } movedItem.order = destination - 1 } else { // 向下移动:将中间元素的order加1,再设置被移动元素的order for i in (destination..<oldIndex).reversed() { itemsArray[i].order += 1 } movedItem.order = destination } } } }
4. 绑定onMove方法
在ForEach的修饰符中添加onMove调用:
ForEach(items) { item in ItemView(item: item) } .onDelete(perform: $items.remove) .onMove(perform: moveItems) // 绑定自定义的移动方法
注意事项
- 新增元素时,要给
order字段设置正确的值(比如当前最大order值+1),避免顺序混乱:func addNewItem(name: String) { let maxOrder = items.max(by: { $0.order < $1.order })?.order ?? -1 let newItem = Item() newItem.name = name newItem.order = maxOrder + 1 $items.append(newItem) } - 所有涉及
order字段的修改都必须在Realm的写事务中进行,确保数据一致性。
内容的提问来源于stack exchange,提问作者BPDev
相关产品推荐
相关产品推荐

