SwiftUI是否存在drag enter类型的拖动手势事件?
SwiftUI 目前没有原生与UIKit touchDragEnter、JavaScript ondragenter完全对等的API,DragGesture确实仅能响应起源于当前视图内部的拖动事件。你可以根据使用场景选择以下两种完全基于官方公开API的实现方案:
方案1:使用DropDelegate(适配跨视图/跨App拖动场景)
如果你的需求是处理系统标准拖动交互(支持从其他视图、甚至其他App拖动内容到当前视图),DropDelegate是官方原生支持的方案,本身提供拖动进入、移动、离开、放下的全生命周期回调:
- 首先创建遵循
DropDelegate协议的自定义类,实现对应回调:
class CustomDropDelegate: DropDelegate { // 拖动进入视图时触发 func dropEntered(info: DropInfo) { // 此处写入拖动进入的处理逻辑 } // 拖动离开视图时触发 func dropExited(info: DropInfo) { // 此处写入拖动离开的处理逻辑 } // 处理内容放下逻辑 func performDrop(info: DropInfo) -> Bool { // 若不需要实际接收放下的内容,直接返回true即可 return true } // 可选:配置拖动时的交互样式 func proposal(for info: DropInfo) -> DropProposal? { return DropProposal(operation: .move) } }
- 给目标视图添加
onDrop修饰符绑定代理即可生效:
YourTargetView() .onDrop(of: [.text], delegate: CustomDropDelegate())
注意:
of参数需要传入你要接收的UTI类型,如果仅需要监听拖动进入/离开事件、不需要实际接收内容,传入通用类型即可。
方案2:全局坐标比对(适配同App内部自定义拖动场景)
如果你处理的是App内部自定义的触摸拖动(不是系统级的内容传递拖动),可以通过比对全局拖动坐标和目标视图的frame实现进入/离开判断:
- 先声明状态变量存储目标视图的全局frame和悬浮状态:
@State private var targetViewFrame: CGRect = .zero @State private var isDragOver = false
- 给目标视图绑定全局frame:
YourTargetView() .background( GeometryReader { geo in Color.clear .onAppear { targetViewFrame = geo.frame(in: .global) } } )
- 在发起拖动的视图的
DragGesture回调中做坐标判断:
YourDraggableView() .gesture( DragGesture(minimumDistance: 0, coordinateSpace: .global) .onChanged { value in let currentIsInside = targetViewFrame.contains(value.location) if currentIsInside != isDragOver { isDragOver = currentIsInside if currentIsInside { // 此处写入拖动进入的处理逻辑 } else { // 此处写入拖动离开的处理逻辑 } } } )
内容的提问来源于stack exchange,提问作者Geri Borbás
相关产品推荐
相关产品推荐

