使用拖动手势向后旋转视图

Rotation of view goes backwards with drag gesture

我有一个观点,我希望能够拖来拖去——有点像一个非自由旋转的命运之轮。拖动在 y 轴和滚轮底部工作正常,但对于 x - 拖动滚轮顶部时视图旋转方向错误。

我很确定这只需要一点额外的逻辑 - 但我尝试过的一切都不起作用 - 例如检查是否 v.startLocation.x < v.location.x.

import SwiftUI

struct SpinningSelectorWheel: View {

var numberOfSegments: Int = 5
private var colorArray:[Color] = [.red, .green, .blue, .yellow, .brown, .gray, .purple, .red, .green, .blue, .yellow, .brown, .gray, .purple]
@State private var angle: CGFloat = 0
@State private var lastAngle: CGFloat = 0
@State private var length : CGFloat = 400
@State private var gtheta: CGFloat = 0
@State private var gstartx: CGFloat = 0
@State private var gstarty: CGFloat = 0

var body: some View {
    GeometryReader
    { fullsize in
        //Text("\(angle)")
        VStack
        {
            Text("\(gtheta)")
            Text("\(gstartx)")
            Text("\(gstarty)")
            Text("\(length)")
        }
        ForEach((1...numberOfSegments).reversed(), id: \.self)
        {segment in
            Path { path in
                path.move(to: CGPoint(x: fullsize.size.width/2, y: fullsize.size.height/2))
                path.addArc(center: .init(x: fullsize.size.width/2, y: fullsize.size.height/2), radius: 150, startAngle: Angle(degrees: Double(1-segment)  * Double(360/numberOfSegments)), endAngle: Angle(degrees: Double(360/numberOfSegments)), clockwise: false)
            }
            .fill(colorArray[segment-1])
        }
        .rotationEffect(.degrees(Double(self.angle))).gesture(DragGesture().onChanged
            { v in
            var theta = (atan2(v.location.x - self.length / 2, self.length / 2 - v.location.y) - atan2(v.startLocation.x - self.length / 2, self.length / 2 - v.startLocation.y)) * 180 / .pi
            gtheta = theta
            gstartx = v.startLocation.x
            gstarty = v.startLocation.y
            if (theta < 0) { theta += 360}
            self.angle = theta + self.lastAngle
            }
            .onEnded { v in
                self.lastAngle = self.angle
            }
        )
    }
}

}

我为 UIKit 写的东西可能适用于 SwiftUI :

// rotation from point lPrevPoint to lTouchPoint
        let lDeltaDirectionX = Double((lTouchPoint.x - lPrevPoint.x) / 2.0)
        let lDeltaDirectionY = Double((lTouchPoint.y - lPrevPoint.y) / 2.0)
// only do 1 direction at a time ( the one with biggest change)
// then you check in which part of the screen you are :
        if abs(lDeltaDirectionX) > abs(lDeltaDirectionY) {
            if lPrevPoint.y > self.frame.size.height / 2.0 {
                orientation = fmod(orientation-lDeltaDirectionX + 360.0, 360.0)
            } else {
                orientation = fmod(orientation+lDeltaDirectionX + 360.0, 360.0)
            }
        }
        else
        {
            if lPrevPoint.x > self.frame.size.width / 2.0 {
                orientation = fmod(orientation+lDeltaDirectionY + 360.0, 360.0)
            } else {
                orientation = fmod(orientation-lDeltaDirectionY + 360.0, 360.0)
            }
        }

orientation 是旋转的角度。不完美,因为它没有考虑到视图中心的距离以获得更准确的值。但可以是一个好的开始。