Search code examples
iosswiftswiftuigesture

Adjust Drag Gesture on Rotated View


I have an image on a view.

  • added rotation to rotate the view
  • added drag gesture to pan the image
  • drag gesture works fine when image is not rotated
  • once the view is rotated to certain angle the drag gesture gets disturbed, since view is rotated.

So, how to adjust the dragOffset and position based on the angle of rotation?

enter image description here

Code:

struct ImageView: View {
    @State private var dragOffset: CGSize = .zero
    @State private var position: CGSize = .zero
    
    @State private var currentRotation: Angle = .zero
    @GestureState private var twistAngle: Angle = .zero
    
    public var body: some View {
        let rotationGesture = RotationGesture(minimumAngleDelta: .degrees(10))
            .updating($twistAngle, body: { (value, state, _) in
                state = value
            })
            .onEnded{ self.currentRotation += $0 }
        
        let dragGesture = DragGesture()
            .onChanged({ (value) in
                self.dragOffset = value.translation
            })
            .onEnded({ (value) in
                self.position.width += value.translation.width
                self.position.height += value.translation.height
                self.dragOffset = .zero
            })
        
        let gestures = rotationGesture
            .simultaneously(with: dragGesture)
        
        Image.placeholder320x192
            .offset(x: dragOffset.width + position.width, y: dragOffset.height + position.height)
            .rotationEffect(currentRotation + twistAngle)
            .gesture(gestures, including: .gesture)
    }
}

Solution

  • The order of the modifiers matter. You currently have the offset before the rotation - therefore you are applying the offset then rotating. This makes the offset appear at an angle. Instead, you want to rotate and then offset.

    Change:

    Image.placeholder320x192
        .offset(x: dragOffset.width + position.width, y: dragOffset.height + position.height)
        .rotationEffect(currentRotation + twistAngle)
        .gesture(gestures, including: .gesture)
    

    To this:

    Image.placeholder320x192
        .rotationEffect(currentRotation + twistAngle)
        .offset(x: dragOffset.width + position.width, y: dragOffset.height + position.height)
        .gesture(gestures, including: .gesture)