SwiftUI如何判断Drag手势释放点是否在视图或自定义Shape内部
解决方案
- 所有SwiftUI的
Shape类型都提供path(in: CGRect)方法返回对应形状的路径,系统原生Path结构体自带contains(_ point: CGPoint)方法,可直接判断点是否在路径范围内,适配任意自定义路径,无需手动编写几何计算逻辑。 - 拖拽手势优先使用目标视图的本地坐标系获取位置,省去全局坐标转本地坐标的额外计算,若必须使用全局坐标系,只需先将全局坐标点转换为目标视图本地坐标再做判断即可。
通用实现代码
可直接替换targetShape为任意系统内置或自定义Shape,无需修改命中判断逻辑:
import SwiftUI struct ContentView: View { let targetSize: CGSize = CGSize(width: 300, height: 300) // 可替换为任意自定义Shape,比如Circle()、Capsule()或者自定义的五角星Shape等 let targetShape: any Shape = Circle() var body: some View { Color.red .overlay( targetShape .fill(.yellow) .frame(width: targetSize.width, height: targetSize.height) .gesture(dragGesture) ) } private var dragGesture: some Gesture { // 直接指定坐标系为目标视图的本地坐标系,拿到的location天然相对于目标视图原点 DragGesture(minimumDistance: 0, coordinateSpace: .local) .onEnded { value in // 生成目标形状在本地坐标系下的路径 let targetPath = targetShape.path(in: CGRect(origin: .zero, size: targetSize)) // 直接调用系统方法判断点是否在路径内 let isInside = targetPath.contains(value.location) print("是否在视图内:\(isInside)") } } }
全局坐标系适配补充
如果你的手势必须使用全局坐标系,只需增加一步坐标转换即可,无需修改命中判断逻辑:
func globalPointToLocal(globalPoint: CGPoint, targetGlobalFrame: CGRect) -> CGPoint { CGPoint( x: globalPoint.x - targetGlobalFrame.minX, y: globalPoint.y - targetGlobalFrame.minY ) } // 目标视图的全局frame可通过GeometryReader读取: // GeometryReader { proxy in // let globalFrame = proxy.frame(in: .global) // }
内容的提问来源于stack exchange,提问作者swiftPunk
相关产品推荐
相关产品推荐

