Search code examples
swiftuimagnification

Strange magnification behavior: scale starts at 1


I want to pinch zoom an image on a view.

I have this code:

@State var progressingScale: CGFloat = 1

var body: some View {
  Image(imageName)
    .resizable()
    .aspectRatio(contentMode: .fit)
    .padding([.leading, .trailing], 20)

    .scaleEffect(progressingScale)

    .gesture(MagnificationGesture()
      .onChanged { value in
          progressingScale = value.magnitude
      }
      .onEnded {value in
        progressingScale = value.magnitude
      }

    )
}

This code works relatively well but suppose I scale the image up and lift the fingers. Now the image is huge.

Then, I try to pinch and scale it up more. The image goes back to scale = 1 and starts scaling up again. I want it to start at the scale it was when the fingers were released the first time.

Cannot figure why... any ideas?


Solution

  • In order for the magnification to stick, you need to keep track of two values: the image's permanent scale (imageScale) and the current magnification value (magnifyBy). The scale applied to the image is the product of these two values (imageScale * magnifyBy).

    While the MagnificationGesture is in progress, just change the magnifyBy property. When the gesture ends, permanently apply the magnification to the imageScale and set magnifyBy back to 1.

    struct ContentView: View {
        @State private var imageScale: CGFloat = 1
        @State private var magnifyBy: CGFloat = 1
        
        var body: some View {
            Image(systemName: "globe")
                .resizable()
                .aspectRatio(contentMode: .fit)
                .padding([.leading, .trailing], 20)
            
                .scaleEffect(imageScale * magnifyBy)
            
                .gesture(MagnificationGesture()
                    .onChanged { value in
                        magnifyBy = value.magnitude
                    }
                    .onEnded {value in
                        imageScale *= value.magnitude
                        magnifyBy = 1
                    }
                         
                )
        }
    }