SwiftUI MagnificationGesture not working properly on Mac

1k Views Asked by At

I have a problem with the MagnificationGesture in SwiftUI on the Mac. I am writing a Mac app and I want to scale a view. When I run the program, it works fine for a couple of times and then the onChanged closure does not get executed anymore. I am afraid this is a bug (or do I completely misunderstand something?). I actually found a very recent question on Reddit, where someone has the exact same issue: https://www.reddit.com/r/SwiftUI/comments/sd43rk/im_having_an_issue_with_the_magnificationgesture/

I could reproduce the problem in a very simple view:

struct ContentView: View {
    var body: some View {
        Text("Hello, world!")
            .padding()
            .gesture(MagnificationGesture()
                        .onChanged({ value in
                print(value)
            }))
    }
}

How can I solve this?

2

There are 2 best solutions below

6
ChrisR On

this is my slightly adapted code – for me it works fine, also after 30 times (macOS 12.2beta, Xcode 13.2.1)

struct ContentView: View {
    
    @State private var scale: CGFloat = 1
    
    var body: some View {
        Text("Hello, world!")
            .scaleEffect(scale)
            .padding()
            .frame(width: 400, height: 400)
            .contentShape(Rectangle())
            .gesture(MagnificationGesture()
                        .onChanged({ value in
                scale = value
                print(value)
            }))
    }
}
3
Chris Macke On

I accidentally found a fix. I'm listening for both drag and magnification. Drag changes the x/y offsets of an image. When magnification stopped responding, dragging the image slightly would make magnification work again. So, at the end of each magnification event, I add a small offset. Seems to work.

Image(nsImage: nsImage)
    .resizable()
    .frame(width: width, height: height)
    .scaleEffect(finalAmount + currentAmount)
    .offset(x: offsetX, y:offsetY)
    .gesture(
        DragGesture()
            .onChanged { value in
                offsetY = value.translation.height + offsetYBuffer
                offsetX =  value.translation.width + offsetXBuffer
            }
            .onEnded { value in
                offsetXBuffer = value.translation.width + offsetXBuffer
                offsetYBuffer = value.translation.height + offsetYBuffer
            }
    ).gesture(
        MagnificationGesture()
            .onChanged { value in
                 currentAmount = value - 1
             }
             .onEnded { value in
                 finalAmount += currentAmount
                 currentAmount = 0
                 offsetY += 0.1 //this seems to fix it
             }
    )