SwiftUI的onMove是“拖动排序列表项”的修饰器,仅限于在List中使用,用于响应用户拖动列表项改变顺序的动作。
基本用法
List {
ForEach(items, id: \.self) { item in
Text(item)
}
.onMove { indices, newOffset in
items.move(fromOffsets: indices, toOffset: newOffset)
}
}
.toolbar { EditButton() }
onMove的函数类型是(IndexSet, Int) -> Void:
indices: IndexSet —— 被移动项的原始索引集合(可以包含多个索引)。
newOffset: Int —— 要插入到的目标索引(插入点的下标)。
也可以使用另一种用法:
List {
ForEach(banks) { bank in
Text(bank.name)
}
.onMove(perform: move)
}
.toolbar { EditButton() }
func move(from source: IndexSet, to destination: Int) {
...
}

使用示例
1、SwiftData中实现排序的功能
SwiftData数据通过@Query实现SwiftUI的查询和排序,需要借助排序字段实现排序:
// 1、新增排序字段
@Model
class PiggyBank {
var sortOrder: Int = 0 // 新增排序字段
}
// 2、修改 Query排序:
@Query(sort: [
SortDescriptor(\PiggyBank.sortOrder),
SortDescriptor(\PiggyBank.creationDate, order: .reverse)
])
var allPiggyBank: [PiggyBank]
// 3、onMove实现排序:
.onMove { indices, newOffset in
var banks = allPiggyBank
banks.move(fromOffsets: indices, toOffset: newOffset)
// 更新所有 sortOrder
for (index, bank) in banks.enumerated() {
bank.sortOrder = index
}
try? context.save()
}
onMove移动列表项后,复制一个临时数组存储当前的所有存钱罐列表,move方法移动对应元素,之后根据临时数组的排序,修改sortOrder排序字段,从而实现修改SwiftData排序的功能。
注意:Query查询顺序不要出错,如果显示反向排序,和for-in的排序正向排序存在不一致,显示排序就会出现问题。
注意事项
1、Xcode Preview环境中无法触发onMove方法
需要在模拟器或真机中使用,Preview环境中无法触发onMove方法,拖动时列表视图可能无法正常显示。
2、ForEach的id如果不稳定,可能导致移动后UI闪烁或数据错位。
总结
onMove 是 SwiftUI 提供的用于响应用户在列表中拖动并重排行的事件回调。它本身不修改数据,需要开发者手动处理移动的索引和排序。
通常配合ForEach / List使用,还可以配合onDelete进行删除操作,也可以在编辑模式EditButton() 启用排序功能。
.toolbar { EditButton() } // 显示系统的“编辑”按钮
// 或者强制编辑模式:
.environment(\.editMode, .constant(.active))
相关文章
1、SwiftUI滚动内容ScrollView:https://fangjunyu.com/2024/12/20/swiftui%e6%bb%9a%e5%8a%a8%e5%86%85%e5%ae%b9scrollview/
