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

SwiftUI中如何检测视图重叠?含半入判定场景示例

SwiftUI中检测视图相交/重叠

一、针对你的具体需求:判断小红圆是否过半进入大蓝圆

你的场景是两个圆形视图,我们可以结合几何特性简化计算,也可以通过获取视图实际位置实现精确判断。以下是完整实现代码:

struct ContentView: View {
    @State private var offset = CGSize.zero
    // 存储两个圆的全局坐标frame
    @State private var blueCircleFrame = CGRect.zero
    @State private var redCircleFrame = CGRect.zero

    var body: some View {
        VStack {
            Circle()
                .fill(.blue)
                .frame(width: 200, height: 200)
                .background(
                    GeometryReader { proxy in
                        Color.clear.onAppear {
                            blueCircleFrame = proxy.frame(in: .global)
                        }
                    }
                )
            
            Circle()
                .fill(.red)
                .frame(width: 100, height: 100)
                .offset(offset)
                .background(
                    GeometryReader { proxy in
                        Color.clear.onAppear {
                            redCircleFrame = proxy.frame(in: .global)
                        }
                    }
                )
                .gesture(
                    DragGesture()
                        .onChanged { gesture in
                            // 更新偏移量
                            let deltaX = gesture.translation.width - (offset.width ?? 0)
                            let deltaY = gesture.translation.height - (offset.height ?? 0)
                            offset = gesture.translation
                            // 实时更新小红圆的全局frame
                            redCircleFrame = redCircleFrame.offsetBy(dx: deltaX, dy: deltaY)
                        }
                        .onEnded { _ in
                            let isHalfInside = isRedCircleHalfInsideBlueCircle()
                            print("小红圆是否过半进入大蓝圆:\(isHalfInside)")
                        }
                )
        }
    }
    
    private func isRedCircleHalfInsideBlueCircle() -> Bool {
        // 计算两个圆的圆心坐标
        let blueCenter = CGPoint(x: blueCircleFrame.midX, y: blueCircleFrame.midY)
        let redCenter = CGPoint(x: redCircleFrame.midX, y: redCircleFrame.midY)
        
        // 计算圆心之间的直线距离
        let distance = hypot(redCenter.x - blueCenter.x, redCenter.y - blueCenter.y)
        
        // 大蓝圆半径100,小红圆半径50
        // 当小红圆过半进入时,圆心距离 ≤ 大蓝圆半径 - 小红圆半径的一半
        return distance <= (100 - 25)
    }
}

实现说明:

  • 用GeometryReader获取视图的全局坐标frame,确保位置计算的准确性
  • 拖动过程中实时更新小红圆的frame,避免位置偏差
  • 利用圆形几何特性简化判断,无需复杂的重叠区域计算

二、通用的视图相交/重叠检测方法

如果是任意形状的视图,可以通过以下方式实现相交或重叠比例判断:

1. 基础相交检测(判断是否有重叠)

private func isViewsOverlapping(frame1: CGRect, frame2: CGRect) -> Bool {
    return frame1.intersects(frame2)
}

2. 计算重叠区域面积(判断重叠比例)

如果需要判断重叠是否超过一定比例,可以计算重叠区域的面积:

private func overlappingArea(frame1: CGRect, frame2: CGRect) -> CGFloat {
    let intersectionRect = frame1.intersection(frame2)
    return intersectionRect.width * intersectionRect.height
}

// 判断小红圆是否过半与大蓝圆重叠
private func isRedCircleHalfOverlapping() -> Bool {
    let redTotalArea = redCircleFrame.width * redCircleFrame.height
    let overlapArea = overlappingArea(frame1: blueCircleFrame, frame2: redCircleFrame)
    return overlapArea >= redTotalArea / 2
}

注意事项:

  • 必须确保所有frame处于同一坐标系(比如统一使用.global),否则计算结果会出错
  • 对于非矩形视图,用CGRect计算的重叠面积是外接矩形的重叠,会存在误差;如果需要精确的形状重叠判断,需结合Path进行更复杂的几何计算

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 20:32:35