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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 10:45:03