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

SwiftUI中能否让onDrag函数触发时机改为触摸按下而非长按?

SwiftUI 修改onDrag触发时机为触摸按下

可以实现将onDrag的触发逻辑从默认的长按改为触摸按下。系统默认的onDrag绑定了长按手势,要修改触发时机,需要通过自定义手势组合替代默认逻辑,直接在触摸按下时启动拖拽流程。

核心实现思路

使用DragGesture并将其minimumDistance设为0(确保触摸按下瞬间触发),结合GestureState跟踪拖拽状态,手动模拟系统onDrag的拖拽数据传递逻辑,同时配合onDrop完成项目重新排序(对应你提到的LazyGrid场景)。

完整示例代码

import SwiftUI

struct ReorderableGrid: View {
    @State private var items = (1...20).map { "Item \($0)" }
    @GestureState private var currentDraggingItem: String? = nil
    
    private let gridColumns = [GridItem(.flexible()), GridItem(.flexible())]
    
    var body: some View {
        ScrollView {
            LazyVGrid(columns: gridColumns, spacing: 16) {
                ForEach(items, id: \.self) { item in
                    Text(item)
                        .padding()
                        .background(currentDraggingItem == item ? .gray.opacity(0.6) : .blue)
                        .foregroundColor(.white)
                        .cornerRadius(8)
                        // 自定义触摸按下触发的拖拽手势
                        .gesture(
                            DragGesture(minimumDistance: 0)
                                .updating($currentDraggingItem) { _, state, _ in
                                    state = item
                                }
                                .onChanged { _ in
                                    // 手动创建拖拽数据提供者,模拟onDrag的核心逻辑
                                    let itemProvider = NSItemProvider(object: item as NSString)
                                }
                        )
                        // 处理放置逻辑
                        .onDrop(of: [.text], delegate: GridDropDelegate(targetItem: item, items: $items, draggingItem: $currentDraggingItem))
                }
            }
            .padding()
        }
    }
}

// 自定义DropDelegate处理拖拽放置后的排序
struct GridDropDelegate: DropDelegate {
    let targetItem: String
    @Binding var items: [String]
    @Binding var draggingItem: String?
    
    func performDrop(info: DropInfo) -> Bool {
        guard let draggedItem = draggingItem, draggedItem != targetItem else { return false }
        
        guard let sourceIndex = items.firstIndex(of: draggedItem),
              let targetIndex = items.firstIndex(of: targetItem) else { return false }
        
        withAnimation {
            items.move(fromOffsets: IndexSet(integer: sourceIndex),
                       toOffset: targetIndex > sourceIndex ? targetIndex + 1 : targetIndex)
        }
        
        draggingItem = nil
        return true
    }
    
    func dropEntered(info: DropInfo) {
        // 可选:添加拖拽进入时的视觉反馈,比如缩放目标视图
    }
}

struct ReorderableGrid_Previews: PreviewProvider {
    static var previews: some View {
        ReorderableGrid()
    }
}

关键细节说明

  • DragGesture(minimumDistance: 0):将手势的最小触发距离设为0,确保触摸按下的瞬间就触发拖拽逻辑,替代默认的长按等待。
  • GestureState:实时跟踪当前拖拽的项目,用于提供即时视觉反馈(比如拖拽时改变视图背景色)。
  • NSItemProvider:系统onDrag内部会自动创建该对象传递拖拽数据,自定义手势时需要手动生成,保证onDrop能识别拖拽的内容。
  • DropDelegate:负责处理拖拽放置后的位置更新,实现LazyGrid内的项目重新排序逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 15:45:38