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

如何限制SwiftUI可拖拽元素沿圆弧移动且避免跨边跳转?

实现圆弧范围内的拖拽手柄(限制13°-272°)

我正尝试实现一个可沿圆弧拖拽的圆形手柄,拖拽范围限定在13度到272度的圆弧区间内,效果类似滑块但沿部分圆弧轨迹。要求手柄到达圆弧端点时停止移动,而非突然跳转到另一侧继续滑动。

以下是演示该问题的SwiftUI View代码:

struct DraggableCircleView: View {
    @State private var angle: Double = 13 // 初始角度13度

    private let minAngle: Double = 13
    private let maxAngle: Double = 272
    private let size: CGFloat = 300
    private let handleSize: CGFloat = 20

    var body: some View {
        ZStack {
            Circle()
                .stroke(lineWidth: 2)
                .foregroundColor(.gray)
                .frame(width: size, height: size)
            
            Circle()
                .frame(width: handleSize, height: handleSize)
                .foregroundColor(.blue)
                .position(position(for: angle, in: CGRect(x: 0, y: 0, width: size, height: size)))
                .gesture(DragGesture()
                    .onChanged { value in
                        let center = CGPoint(x: size / 2, y: size / 2)
                        let newLocation = CGPoint(x: center.x + value.translation.width, y: center.y + value.translation.height)
                        let newAngle = angle(from: newLocation, center: center)
                        if newAngle >= minAngle && newAngle <= maxAngle {
                            self.angle = newAngle
                        } else if newAngle < minAngle {
                            self.angle = minAngle
                        } else if newAngle > maxAngle {
                            self.angle = maxAngle
                        }
                    }
                )
        }
    }

    func angle(from location: CGPoint, center: CGPoint) -> Double {
        let dx = location.x - center.x
        let dy = location.y - center.y
        let radians = atan2(dy, dx)
        let degrees = radians * 180 / .pi
        let adjustedDegrees = degrees < 0 ? degrees + 360 : degrees
        return adjustedDegrees
    }

    func position(for angle: Double, in rect: CGRect) -> CGPoint {
        let radius = Double(min(rect.width, rect.height) / 2 - handleSize / 2)
        let center = CGPoint(x: rect.midX, y: rect.midY)
        let radians = angle * .pi / 180
        return CGPoint(
            x: center.x + CGFloat(radius * cos(radians)),
            y: center.y + CGFloat(radius * sin(radians))
        )
    }
}

我认为需要在角度被限制(比如设置self.angle为minAngle或maxAngle时)中断DragGesture,但尚未找到通过代码中断拖拽手势的示例。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 19:37:41