SwiftUI实现长按拖动调整列表项排序功能求助
SwiftUI实现类似Safari标签页的长按拖动排序功能
以下是修改后的完整代码,实现长按列表项拖动调整排序的功能,和Safari标签页的交互逻辑一致:
import SwiftUI struct HomeView: View { struct Item: Identifiable { var id = UUID() var name: String var color: Color } @State var items = [ Item(name: "Item 1", color: .red), Item(name: "Item 2", color: .green), Item(name: "Item 3", color: .blue) ] // 跟踪当前拖动的元素、初始索引和偏移量 @State private var draggedItem: Item? @State private var initialIndex: Int? @State private var dragOffset: CGSize = .zero var body: some View { List { ForEach(items.indices, id: \.self) { index in let item = items[index] Text(item.name) .frame(maxWidth: .infinity) .padding() .background(item.color) .foregroundColor(.white) .cornerRadius(8) // 给拖动中的元素添加偏移和视觉效果 .offset(draggedItem?.id == item.id ? dragOffset : .zero) .shadow(color: draggedItem?.id == item.id ? .black.opacity(0.3) : .clear, radius: 8) .zIndex(draggedItem?.id == item.id ? 1 : 0) .onLongPressGesture(minimumDuration: 0.2) { // 长按开始,记录当前元素和初始索引 draggedItem = item initialIndex = index } .simultaneousGesture( DragGesture() .onChanged { value in guard draggedItem != nil else { return } // 更新拖动偏移量 dragOffset = value.translation // 计算当前拖动位置对应的目标索引 let currentY = value.location.y let rowHeight: CGFloat = 60 // 预估行高,可根据实际调整 let targetIndex = max(0, min(items.count - 1, Int(currentY / rowHeight))) // 如果目标索引和初始索引不同,交换元素 if let initialIdx = initialIndex, initialIdx != targetIndex { items.swapAt(initialIdx, targetIndex) initialIndex = targetIndex } } .onEnded { _ in // 拖动结束,重置状态 draggedItem = nil initialIndex = nil dragOffset = .zero } ) } .onDelete(perform: deleteItem) } } func deleteItem(at offsets: IndexSet) { items.remove(atOffsets: offsets) } } struct HomeView_Previews: PreviewProvider { static var previews: some View { HomeView() } }
关键实现说明:
- 状态变量:通过
draggedItem跟踪当前拖动的元素,initialIndex记录元素初始位置,dragOffset控制拖动时的视图偏移。 - 长按触发:用
.onLongPressGesture设置短时长触发(0.2秒),触发后记录当前元素和索引。 - 拖动交互:通过
.simultaneousGesture绑定DragGesture,拖动过程中实时更新偏移量,同时根据手指位置计算目标索引,交换数组元素实现排序。 - 视觉反馈:拖动中的元素会提升层级(
zIndex)、添加阴影和偏移,让用户清晰看到拖动状态。
注意:代码中rowHeight是预估的行高度,如果你的列表项高度不同,可以根据实际情况调整,或者通过GeometryReader动态获取行高来提升准确性。
内容的提问来源于stack exchange,提问作者NexusUA
相关产品推荐
相关产品推荐

