SwiftUI:旋转后便签移动不正确

问题描述 投票:0回答:1

我正在开发一个 SwiftUI 项目,我可以在其中拖动便笺、调整大小和旋转便笺。虽然调整大小和旋转工作正常,但旋转便签后我遇到了拖动行为的问题。

问题:

当便签旋转时,沿着“垂直”或“水平”轴拖动它会导致沿着原始未旋转的轴移动。例如,如果便签旋转 90 度,则向上拖动它会使其横向移动。

我尝试过的:

  • 我使用rotationEffect来处理旋转。
  • 我正在使用三角函数调整平移以解释旋转,但拖动仍然无法正确运行。

这是我的便签代码:

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
            }
    }
}
ios swift xcode swiftui
1个回答
0
投票

无需调整旋转的平移,只需让修改器为您完成工作即可。

因此不需要静态函数

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
}
© www.soinside.com 2019 - 2024. All rights reserved.