Search code examples
iosswiftuigesture

cpu runs at full speed when placing offset after gesture


I want to drag the image along y-axis. It seems quite simple. However I put the "offset" following the "gesture" by mistake. Then cpu runs at full speed and UI becomes irresponsive.

Everything is ok by reordering "offset" before "gesture". But I can't figure it out.

struct ContentView: View {
    @State private var currentPosition: CGSize = .zero
    @State private var newPosition: CGSize = .zero
    var body: some View {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundColor(.accentColor)
//                .offset(x: currentPosition.width, y: currentPosition.height)
                .gesture(DragGesture()
                    .onChanged { value in
                        print("DragEffectViewModifier-ondrag")
                        currentPosition = CGSize(width: 0, height: value.translation.height + newPosition.height)
                    }
                    .onEnded { value in
                        newPosition = currentPosition
                    })
                .offset(x: currentPosition.width, y: currentPosition.height)
    }
}

EDIT:

"DragEffectViewModifier-ondrag" displays on the console repeatedly. What leads to the "cycle behavior"? It makes cpu to run at full speed and UI to become irresponsive when "offset" placed below "gesture"


Solution

  • I am away from a system to try your code, but looking at it I think that something like this is happening… the struct is created, once created, the state vars are initialised and this causes the body var to be to be evaluated, as it is evaluated, the DragGesture is also recreated and initialises its onChanged, which re-write currentPostion which causes the body var to be re-evaluated, which recreates the DragGesture, and so on.

    To confirm or deny my reasoning, I would move the DragGesture to be a var outside of the body and then inject the gesture as something like .gesture(dragGesture). That appears to be the kind of pattern that I seen on examples of gesture usage. The idea being to have the gesture as a semi-singleton rather than a new gesture being re-created each time the body var is evaluated.

    Just a guess.

    OK..... my above response was BS (poorly considered)... I tried your code and got exactly as you described. The correct is at SwiftUI: Error in dragging logic or is this a bug?

    Which explains that it related to the coordinate spaces that offset and drag operate in.

    TL;DR Change DragGesture creation to

                .gesture(DragGesture(coordinateSpace: .global)
    

    and it works as expected.