admin管理员组

文章数量:1393859

We have made it possible to scale, rotate, and move images using SwiftUI. The movement gesture is implemented independently, while the zoom and rotation gestures can be performed simultaneously using SimultaneousGesture.

When repeatedly performing image zoom gestures, at some point the image seemed to freeze, and any further zoom, rotation, or movement gestures were no longer possible.

I would like to know the code that will solve this problem and make it possible to permanently scale images.

import SwiftUI

struct ContentView: View {

    @State private var offset: CGSize = .zero // drag value
    @State private var lastOffset: CGSize = .zero // hold last drag value
    @State private var scale: CGFloat = 1.0 // pinch scale value
    @State private var lastScale: CGFloat = 1.0 // hold last scale value
    @State private var angle: Angle = .zero // pinch angle value
    @State private var lastAngle: Angle = .zero // hold last angle value
    @State private var isReset: Bool = false

    let minScale = 0.2 // minimum scale value
    let maxScale = 5.0 // maximum scale value

    var dragGesture: some Gesture { // Move
        DragGesture()
            .onChanged {
                offset = CGSize(width: lastOffset.width + $0.translation.width, height: lastOffset.height + $0.translation.height)
            }
            .onEnded { _ in
                lastOffset = offset
            }
    }
    var scaleGesture: some Gesture { // Scaling
        MagnificationGesture()
            .onChanged {
                if ($0 > minScale) && ($0 < maxScale) { // scaling range for pinch
                    scale = $0 * lastScale
                }
            }
            .onEnded { _ in
                lastScale = scale
            }
    }
    var rotateGesture: some Gesture { // rotate
        RotationGesture(minimumAngleDelta: .degrees(8)) // minimun start angle = 8degrees
            .onChanged {
                angle = $0 + lastAngle
            }
            .onEnded { _ in
                lastAngle = angle
            }
    }

    var body: some View {
        NavigationStack {
        
            VStack {
                GeometryReader { geometry in
                
                    Image(systemName: "globe")
                        .resizable()
                        .scaledToFit()
                        .frame(maxWidth: .infinity, maxHeight: .infinity) // placement size
                        .rotationEffect(angle, anchor: .center) // rotationEffect must be first
                        .scaleEffect(scale) // scaleEffect must be after rotationEffect
                        .offset(offset) // offset is last
                        .gesture(dragGesture)
                        .gesture(SimultaneousGesture(rotateGesture, scaleGesture))
                }
                .toolbar {
                    ToolbarItem(placement: .topBarLeading) {
                        Spacer()
                    }
                    ToolbarItem(placement: .topBarTrailing) {
                        Button(action: {
                            isReset = true
                        }) {
                            Image(systemName: "arrow.trianglehead.clockwise")
                                .font(.title)
                                .foregroundColor(.red)
                        }
                    }
                }
            
            }
        }
        .onChange(of: isReset) {
            if (isReset == true) {
                offset = .zero; lastOffset = .zero
                scale = 1.0; lastScale = 1.0
                angle = .zero; lastAngle = .zero
            }
        
            isReset = false
        }
    }
}

We have made it possible to scale, rotate, and move images using SwiftUI. The movement gesture is implemented independently, while the zoom and rotation gestures can be performed simultaneously using SimultaneousGesture.

When repeatedly performing image zoom gestures, at some point the image seemed to freeze, and any further zoom, rotation, or movement gestures were no longer possible.

I would like to know the code that will solve this problem and make it possible to permanently scale images.

import SwiftUI

struct ContentView: View {

    @State private var offset: CGSize = .zero // drag value
    @State private var lastOffset: CGSize = .zero // hold last drag value
    @State private var scale: CGFloat = 1.0 // pinch scale value
    @State private var lastScale: CGFloat = 1.0 // hold last scale value
    @State private var angle: Angle = .zero // pinch angle value
    @State private var lastAngle: Angle = .zero // hold last angle value
    @State private var isReset: Bool = false

    let minScale = 0.2 // minimum scale value
    let maxScale = 5.0 // maximum scale value

    var dragGesture: some Gesture { // Move
        DragGesture()
            .onChanged {
                offset = CGSize(width: lastOffset.width + $0.translation.width, height: lastOffset.height + $0.translation.height)
            }
            .onEnded { _ in
                lastOffset = offset
            }
    }
    var scaleGesture: some Gesture { // Scaling
        MagnificationGesture()
            .onChanged {
                if ($0 > minScale) && ($0 < maxScale) { // scaling range for pinch
                    scale = $0 * lastScale
                }
            }
            .onEnded { _ in
                lastScale = scale
            }
    }
    var rotateGesture: some Gesture { // rotate
        RotationGesture(minimumAngleDelta: .degrees(8)) // minimun start angle = 8degrees
            .onChanged {
                angle = $0 + lastAngle
            }
            .onEnded { _ in
                lastAngle = angle
            }
    }

    var body: some View {
        NavigationStack {
        
            VStack {
                GeometryReader { geometry in
                
                    Image(systemName: "globe")
                        .resizable()
                        .scaledToFit()
                        .frame(maxWidth: .infinity, maxHeight: .infinity) // placement size
                        .rotationEffect(angle, anchor: .center) // rotationEffect must be first
                        .scaleEffect(scale) // scaleEffect must be after rotationEffect
                        .offset(offset) // offset is last
                        .gesture(dragGesture)
                        .gesture(SimultaneousGesture(rotateGesture, scaleGesture))
                }
                .toolbar {
                    ToolbarItem(placement: .topBarLeading) {
                        Spacer()
                    }
                    ToolbarItem(placement: .topBarTrailing) {
                        Button(action: {
                            isReset = true
                        }) {
                            Image(systemName: "arrow.trianglehead.clockwise")
                                .font(.title)
                                .foregroundColor(.red)
                        }
                    }
                }
            
            }
        }
        .onChange(of: isReset) {
            if (isReset == true) {
                offset = .zero; lastOffset = .zero
                scale = 1.0; lastScale = 1.0
                angle = .zero; lastAngle = .zero
            }
        
            isReset = false
        }
    }
}
Share Improve this question asked Mar 27 at 13:50 BB-8BB-8 1075 bronze badges 3
  • You will be able to instantly find a problem if you simply add some print statements inside the changed and on ended clauses. I can't really figure out all your code, but I'm guessing you almost certainly need to do something as well when the gesture begins as well as change and end, and don't fet cancel as well. As I say, if you just add print statements, you'll instantly find the problem. Writing touch related code is very subtle and tricky. – Fattie Commented Mar 27 at 17:51
  • I checked the situation using the print statement, but couldn't determine the cause, so I submitted Feedback to Apple. FB17031685 – BB-8 Commented Mar 28 at 5:59
  • Since MagnificationGesture is already deprecated, I checked using MagnifyGesture but I am getting the same issue. – BB-8 Commented Mar 28 at 6:00
Add a comment  | 

1 Answer 1

Reset to default -1

This issue does not occur if you define the image scaling gesture alone.

Problems arise when SimultaneousGesture allows multiple gestures to be performed simultaneously.

.gesture(scaleGesture)  --->  No problems occur

.gesture(SimultaneousGesture(rotateGesture, scaleGesture))  ----> Problems occur

本文标签: iosImage scaling is disabled in SwiftUIStack Overflow