charelf
charelf

Reputation: 3845

SwiftUI gesture state is reset between gestures

I have the following code for a simple square to which I attach a MagnificationGesture to update its state with a pinch to zoom gesture.

import SwiftUI

struct ContentView2: View {
    
    var scale: CGFloat = 1
    
    var magnificationGesture: some Gesture {
        MagnificationGesture()
            .onChanged { value in
                scale = value
            }
    }
    
    var body: some View {
        VStack {
            Text("\(scale)")
            Spacer()
            Rectangle()
                .fill(Color.red)
                .scaleEffect(self.scale)
                .gesture(
                    magnificationGesture
                )
            Spacer()
        }
    }
}

struct ContentView2_Previews: PreviewProvider {
    static var previews: some View {
        ContentView2()
    }
}

However this simple view behaves weird. When I perform the gesture, the scale @State property is succesfully modified. However when I then do another gesture with my hands, the scale property is reset to its initial state, instead of starting from its current value.

Here is a video of what happens. For example, when the red view is very small, performing the gesture, I would expect that it stays small, instead of completely resetting.

How can I get the desired behaviour - that is - the scale property is not reset

enter image description here

Upvotes: 2

Views: 801

Answers (2)

nickreps
nickreps

Reputation: 1080

I was able to get it working by adding a bit to the code. Check it out and let me know if this works for your use case:

  import SwiftUI

struct ContentView2: View {
    var magGesture = MagnificationGesture()
    @State var magScale: CGFloat = 1
    @State var progressingScale: CGFloat = 1
    
    var magnificationGesture: some Gesture {
        magGesture
            .onChanged { progressingScale = $0 }
            .onEnded {
                magScale *= $0
                progressingScale = 1
            }
    }
    
    var body: some View {
        VStack {
            Text("\(magScale)")
            Spacer()
            Rectangle()
                .fill(Color.red)
                .scaleEffect(self.magScale * progressingScale)
            
                .gesture(
                    magnificationGesture
                )
            Spacer()
        }
    }
}

struct ContentView2_Previews: PreviewProvider {
    static var previews: some View {
        ContentView2()
    }
}

Upvotes: 2

charelf
charelf

Reputation: 3845

I solved it by adding another scale and only updating one of them at the end to keep track of the scale

Code

import SwiftUI

struct ContentView2: View {
    
    @State var previousScale: CGFloat = 1
    @State var newScale: CGFloat = 1
    
    var magnificationGesture: some Gesture {
        MagnificationGesture()
            .onChanged { value in
                newScale = previousScale * value
            }
            .onEnded { value in
                previousScale *= value
            }
    }
    
    var body: some View {
        VStack {
            Text("\(newScale)")
            Spacer()
            Rectangle()
                .fill(Color.red)
                .scaleEffect(newScale)
                .gesture(
                    magnificationGesture
                )
            Spacer()
        }
    }
}

struct ContentView2_Previews: PreviewProvider {
    static var previews: some View {
        ContentView2()
    }
}

Upvotes: 1

Related Questions