我正在尝试创建一个 SwiftUI 视图,其中有一个红色旋钮,可以围绕蓝色矩形平滑旋转。我已经实现了下面的代码,但旋钮似乎在跳跃,而不是像旋钮那样平滑旋转:
import SwiftUI
struct RotatingKnobView: View {
@State private var knobRotation: Double = 0.0
var body: some View {
ZStack {
Rectangle()
.frame(width: 200, height: 100)
.foregroundColor(Color.blue)
Circle()
.frame(width: 40, height: 40)
.foregroundColor(Color.red)
.offset(x: 100, y: 50)
.gesture(
DragGesture()
.onChanged { value in
DispatchQueue.main.async {
withAnimation {
let translation = value.translation.width
let degrees = translation / 2 // Adjust sensitivity as needed
// Update the rotation angle state in degrees
if degrees < 0 {
knobRotation = degrees * -1
} else {
knobRotation = degrees
}
print(knobRotation)
}
}
}
)
}
.rotationEffect(Angle(degrees: knobRotation))
}
}
struct RotatingKnobView_Previews: PreviewProvider {
static var previews: some View {
RotatingKnobView()
}
}
什么可能导致此行为,以及如何使旋钮围绕矩形平滑旋转?
你的示例肯定运行不顺畅,当我在模拟器中运行它时它崩溃了😢
您似乎正在近似计算角度,因此它的跳跃也许并不奇怪。要精确计算,请参阅 SwiftUI - 拖动时抓取圆的角度。
使用该帖子中的解决方案(这是我的答案),这是对您的代码的修改,可以更顺利地工作。我认为拖动手势需要应用于整个形状,而不仅仅是圆形。同样重要的是:必须在旋转效果之后应用手势!
struct RotatingKnobView: View {
@State private var knobRotation: Double = 0.0
private func location2Degrees(location: CGPoint, midX: CGFloat, midY: CGFloat) -> CGFloat {
let radians = location.y < midY
? atan2(location.x - midX, midY - location.y)
: .pi - atan2(location.x - midX, location.y - midY)
let degrees = radians * 180 / .pi
return degrees < 0 ? degrees + 360 : degrees
}
private func applyRotation(width: CGFloat, height: CGFloat) -> some Gesture {
DragGesture()
.onChanged { value in
let midX = width / 2
let midY = height / 2
let startAngle = location2Degrees(location: value.startLocation, midX: midX, midY: midY)
let endAngle = location2Degrees(location: value.location, midX: midX, midY: midY)
let dAngle = endAngle - startAngle
// print(dAngle)
knobRotation = dAngle
}
}
var body: some View {
Rectangle()
.frame(width: 200, height: 100)
.foregroundColor(Color.blue)
.overlay(alignment: .bottomTrailing) {
Circle()
.frame(width: 40, height: 40)
.foregroundColor(Color.red)
.offset(x: 20, y: 20)
}
.rotationEffect(Angle(degrees: knobRotation))
.gesture(applyRotation(width: 200, height: 100))
}
}