Hello,
I have a view in SwiftUI that has both a Drag and Magnification Gesture. Before iOS 15 my app worked with both gestures on the same view. This is how they are composed:
let dragGesture = DragGesture() .onChanged { value in //self.offset = value.translation self.currentPosition = CGSize(width: value.translation.width + self.newPosition.width, height: value.translation.height + self.newPosition.height) } .onEnded { value in withAnimation { self.currentPosition = CGSize(width: value.translation.width + self.newPosition.width, height: value.translation.height + self.newPosition.height) self.newPosition = self.currentPosition self.isDragging = false } } let pressGesture = LongPressGesture() .onEnded { value in withAnimation { self.isDragging = true } } let pressGestureDelete = LongPressGesture(minimumDuration: 3) .onEnded { value in self.deleteBtn = true } let resizeGesture = MagnificationGesture(minimumScaleDelta: 0.1) .onChanged { value in self.scale *= value } .onEnded { value in self.scale *= value } let combined = pressGesture.sequenced(before: dragGesture).simultaneously(with: pressGestureDelete).simultaneously(with: resizeGesture)
And then on my view I am adding the gesture as .gesture(combined)
Since iOS 15 this no longer works. Instead I can drag the view around after the long press, but as soon as I attempt a resize using the magnification gesture the whole app freezes. I have tried attaching the magnification gesture to different pieces of the view thinking that maybe it needs to be at a different level (parent/child) from the drag gesture, but I get the same behavior if there is a drag gesture and a magnification gesture in the same view. It doesn't seem to matter how I attach them, if they both exist in the same view it causes the whole app to become unresponsive.
Does anyone know how to overcome this? Is this the new "intended" functionality? If so what do we do for the users who are accustomed to being able to seamlessly drag something and then resize it?
Thank you in advance.
OH SNAP!!
I figured it out! I was putting things in the wrong order in my view definition!
Here is the final working view, that is both draggable and resizable!!
import SwiftUI struct MovableResizableView<Content>: View where Content: View { @GestureState private var dragState = DragState.inactive @State private var currentScale: CGFloat = 0 @State private var finalScale: CGFloat = 1 @State var width: CGFloat = 150 @State var height: CGFloat = 150 @State private var newPosition: CGSize = .zero @State private var isDragging = false var content: () -> Content var body: some View { content() .opacity(dragState.isPressing ? 0.5 : 1.0) .scaleEffect(finalScale + currentScale) .offset(x: dragState.translation.width + newPosition.width, y: dragState.translation.height + self.newPosition.height) .animation(Animation.easeInOut(duration: 0.1), value: 0) .gesture(LongPressGesture(minimumDuration: 1.0) .sequenced(before: DragGesture()) .updating($dragState, body: { (value, state, transaction) in switch value { case .first(true): state = .pressing case .second(true, let drag): state = .dragging(translation: drag?.translation ?? .zero) default: break } }) .onEnded({ (value) in guard case .second(true, let drag?) = value else { return } self.newPosition.height += drag.translation.height self.newPosition.width += drag.translation.width })) .gesture(MagnificationGesture() .onChanged{ newScale in currentScale = newScale } .onEnded { scale in finalScale = scale currentScale = 0 }) } } struct MovableResizableView_Previews: PreviewProvider { static var previews: some View { MovableResizableView() { Image(systemName: "star.circle.fill") .resizable() .frame(width: 100, height: 100) .foregroundColor(.green) } } }