我正在开发一个 SwiftUI 项目,我可以在其中拖动便笺、调整大小和旋转便笺。虽然调整大小和旋转工作正常,但旋转便签后我遇到了拖动行为的问题。
问题:
当便签旋转时,沿着“垂直”或“水平”轴拖动它会导致沿着原始未旋转的轴移动。例如,如果便签旋转 90 度,则向上拖动它会使其横向移动。
我尝试过的:
这是我的便签代码:
ZStack {
stickyNote.color
.frame(width: stickyNote.size.width, height: stickyNote.size.height)
.cornerRadius(10)
.overlay(
RoundedRectangle(cornerRadius: 10)
.stroke(isSelected ? Color.blue : Color.clear, lineWidth: 3)
)
.rotationEffect(rotation, anchor: .center)
.offset(x: position.width, y: position.height)
.gesture(
TransformHelper.dragGesture(
position: $position,
lastPosition: $lastPosition,
rotation: rotation,
isResizing: isResizing,
isDragging: $isDragging
)
)
.gesture(
TransformHelper.rotationGesture(
rotation: $rotation,
lastRotation: $lastRotation
)
)
}
这里是移动和旋转的代码:
static func adjustTranslationForRotation(_ translation: CGSize, rotation: Angle) -> CGSize {
let radians = rotation.radians
let cosTheta = CGFloat(cos(radians))
let sinTheta = CGFloat(sin(radians))
// Adjust the translation to account for rotation
let adjustedX = translation.width * cosTheta - translation.height * sinTheta
let adjustedY = translation.width * sinTheta + translation.height * cosTheta
return CGSize(width: adjustedX, height: adjustedY)
}
static func dragGesture(
position: Binding<CGSize>,
lastPosition: Binding<CGSize>,
rotation: Angle,
isResizing: Bool,
isDragging: Binding<Bool>
) -> some Gesture {
return DragGesture()
.onChanged { value in
if !isResizing {
let adjustedTranslation = adjustTranslationForRotation(value.translation, rotation: rotation)
position.wrappedValue = CGSize(
width: lastPosition.wrappedValue.width + adjustedTranslation.width,
height: lastPosition.wrappedValue.height + adjustedTranslation.height
)
isDragging.wrappedValue = true
}
}
.onEnded { _ in
if isDragging.wrappedValue {
isDragging.wrappedValue = false
lastPosition.wrappedValue = position.wrappedValue
}
}
}
有人遇到过类似的问题,即应用旋转后拖动方向不正确吗?任何关于如何使便签根据其当前方向正确移动的建议将不胜感激!
提前致谢!
编辑:这是一个最小的繁殖示例
import SwiftUI
struct StickyNoteView: View {
@State private var position: CGSize = .zero
@State private var lastPosition: CGSize = .zero
@State private var rotation: Angle = .zero
@State private var lastRotation: Angle = .zero
@State private var isDragging: Bool = false
var body: some View {
ZStack {
Rectangle()
.fill(Color.yellow)
.frame(width: 200, height: 200)
.rotationEffect(rotation)
.offset(x: position.width, y: position.height)
.gesture(
TransformHelper.dragGesture(
position: $position,
lastPosition: $lastPosition,
rotation: rotation,
isResizing: false,
isDragging: $isDragging
)
)
.gesture(
TransformHelper.rotationGesture(
rotation: $rotation,
lastRotation: $lastRotation
)
)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(Color.gray.opacity(0.3))
.edgesIgnoringSafeArea(.all)
}
}
import SwiftUI
struct TransformHelper {
// Adjust the translation to account for the center of the StickyNote
static func adjustTranslationForRotation(_ translation: CGSize, rotation: Angle) -> CGSize {
let radians = rotation.radians
let cosTheta = CGFloat(cos(radians))
let sinTheta = CGFloat(sin(radians))
// Transformation der Translation in das rotierte Koordinatensystem
let adjustedX = translation.width * cosTheta - translation.height * sinTheta
let adjustedY = translation.width * sinTheta + translation.height * cosTheta
return CGSize(width: adjustedX, height: adjustedY)
}
// Drag Gesture Handler
static func dragGesture(
position: Binding<CGSize>,
lastPosition: Binding<CGSize>,
rotation: Angle,
isResizing: Bool,
isDragging: Binding<Bool>
) -> some Gesture {
return DragGesture()
.onChanged { value in
if !isResizing {
let adjustedTranslation = adjustTranslationForRotation(value.translation, rotation: rotation)
position.wrappedValue = CGSize(
width: lastPosition.wrappedValue.width + adjustedTranslation.width,
height: lastPosition.wrappedValue.height + adjustedTranslation.height
)
isDragging.wrappedValue = true
}
}
.onEnded { _ in
if isDragging.wrappedValue {
isDragging.wrappedValue = false
lastPosition.wrappedValue = position.wrappedValue
}
}
}
// Rotation Gesture Handler
static func rotationGesture(
rotation: Binding<Angle>,
lastRotation: Binding<Angle>
) -> some Gesture {
return RotationGesture()
.onChanged { angle in
rotation.wrappedValue = lastRotation.wrappedValue + angle
}
.onEnded { angle in
lastRotation.wrappedValue += angle
}
}
}
无需调整旋转的平移,只需让修改器为您完成工作即可。
因此不需要静态函数
adjustTranslationForRotation
,函数dragGesture
可以更改如下:
// static func dragGesture
if !isResizing {
// let adjustedTranslation = adjustTranslationForRotation(value.translation, rotation: rotation)
position.wrappedValue = CGSize(
width: lastPosition.wrappedValue.width + value.translation.width,
height: lastPosition.wrappedValue.height + value.translation.height
)
isDragging.wrappedValue = true
}