2

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?

Mark Rotteveel
  • 100,966
  • 191
  • 140
  • 197
  • do you magnify with the trackpad? Obviously the magnifying stops when you hit the edges of the trackpad. But in general it works fine with me ... Also you have to start the gesture directly on the TextView, which can be tricky. A larger frame with `.contentShape(Rectangle())` can help. – ChrisR Feb 01 '22 at 00:05
  • I do magnify with the trackpad. I initially had this issue with a much larger view, so I am definitely doing the gesture on the view. How many times have you tried magnifying? At me it stops after maybe pinching 15 times or so... – Frederik Mrozek Feb 01 '22 at 00:14

2 Answers2

2

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
             }
    )
Chris Macke
  • 56
  • 1
  • 6
  • 1
    This indeed seems to work. So in a real project, you would probably add a very small offset alternately plus and minus, so that the offset does not grow too much over time. Both adding and subtracting in the `.onEnded` block in the same call does not work... – Frederik Mrozek Nov 22 '22 at 08:35
  • 1
    One more "fix." I noticed that pinch gestures stopped working across all apps simultaneously. Open the Photos app and you'll see it malfunctioning as well. There's a discussion on the Apple forums. Placing your fingers further apart before your gesture makes it start working again. https://discussions.apple.com/thread/253369850 – Chris Macke Nov 25 '22 at 04:12
  • Indeed. When I read the discussion on the Apple forum, I recalled that the magnification gesture stopped working in Affinity Designer sometimes too. I never had the idea this could be the same problem. Your workaround with the offset seems to work though. – Frederik Mrozek Nov 25 '22 at 10:44
1

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)
            }))
    }
}
ChrisR
  • 9,523
  • 1
  • 8
  • 26
  • Hmm, I tried this out and at first it seemed like it works. But then I noticed, that when I zoom out for a couple of times, it stops working again. And I am sure that I hit the gesture area. I currently use macOS 12.1, Xcode 13.2.1 – Frederik Mrozek Feb 01 '22 at 08:15
  • I'll try this out on an other device. Maybe there's something is broken only side... – Frederik Mrozek Feb 01 '22 at 08:20
  • I asked a friend to try this on his computer with exactly your code and he could actually reproduce this issue. It didn't always happen very quickly, but it did eventually. – Frederik Mrozek Feb 01 '22 at 08:36
  • That's disturbing ... let me also check on another device – ChrisR Feb 01 '22 at 10:59
  • I tried it on a third device now and although it took way longer of zooming in and out, but I could reproduce the issue there too. The MagnificationGesture just stopped working at some point... – Frederik Mrozek Feb 01 '22 at 13:34
  • I did too (macOS 12.0.1) ... was able reproduce the issue at first run immediately, then not anymore at all... very strange – does anyone out there have an idea? – ChrisR Feb 01 '22 at 13:51