You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI中如何使用onMove实现横向列表的拖拽重排序?

实现横向可拖拽重排的列表

要把纵向可拖拽的List改成横向排列并保留重排功能,你需要替换原生List为横向滚动容器,同时自定义拖拽和放置的逻辑,具体实现如下:

完整代码

import SwiftUI

struct HorizontalReorderableList: View {
    @State private var contacts = [
        "John",
        "Alice",
        "Bob",
        "Foo",
        "Bar"
    ]
    @State private var draggedItem: String?
    
    var body: some View {
        ScrollView(.horizontal) {
            LazyHStack(spacing: 16) {
                ForEach(contacts, id: \.self) { contact in
                    Text(contact)
                        .padding()
                        .background(Color.gray.opacity(0.2))
                        .cornerRadius(8)
                        .onDrag {
                            draggedItem = contact
                            return NSItemProvider(object: contact as NSString)
                        }
                        .onDrop(of: [.text], delegate: DropViewDelegate(
                            item: contact,
                            listData: $contacts,
                            draggedItem: $draggedItem
                        ))
                }
            }
            .padding()
        }
    }
}

// 处理放置逻辑的代理
struct DropViewDelegate: DropDelegate {
    let item: String
    @Binding var listData: [String]
    @Binding var draggedItem: String?
    
    func performDrop(info: DropInfo) -> Bool {
        guard let draggedItem = draggedItem, draggedItem != item else { return false }
        
        if let fromIndex = listData.firstIndex(of: draggedItem),
           let toIndex = listData.firstIndex(of: item) {
            withAnimation {
                listData.move(fromOffsets: IndexSet(integer: fromIndex), toOffset: toIndex > fromIndex ? toIndex + 1 : toIndex)
            }
            self.draggedItem = nil
            return true
        }
        return false
    }
    
    func dropEntered(info: DropInfo) {
        guard let draggedItem = draggedItem, draggedItem != item else { return }
        
        if let fromIndex = listData.firstIndex(of: draggedItem),
           let toIndex = listData.firstIndex(of: item) {
            if listData[toIndex] != draggedItem {
                withAnimation {
                    listData.move(fromOffsets: IndexSet(integer: fromIndex), toOffset: toIndex > fromIndex ? toIndex + 1 : toIndex)
                }
            }
        }
    }
    
    func dropUpdated(info: DropInfo) -> DropProposal? {
        return DropProposal(operation: .move)
    }
}

#Preview {
    HorizontalReorderableList()
}

关键实现说明

  • 横向容器:用ScrollView(.horizontal)提供横向滚动能力,内部配合LazyHStack(适合大量元素时提升性能)排列列表项。
  • 拖拽触发:通过onDrag手势记录当前被拖拽的元素,并提供拖拽数据。
  • 放置处理:自定义DropViewDelegate监听拖拽进入、更新和完成事件,调用move(fromOffsets:toOffset:)调整数组顺序,同时添加动画让重排过程更流畅。

内容的提问来源于stack exchange,提问作者Nicolas Gimelli

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 18:20:33