Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI -- Detect DragGesture cancellation when iPad dock is pulled up

Tags:

ios

swiftui

Here is a very simple example to show what I try to do. The red circle can be dragged around and when it is released it will go back to the original place, as shown in the first image. The problem occurs when iPad dock is pulled up in the middle of dragging and then the DragGesture's .onEnded will never be called and the red circle is stuck, as shown in the second image. I don't understand why .onEndedisn't called. What am I missing here?

I thought of a workaround by resetting offset in SceneDelegate's sceneDidBecomeActive, but it doesn't work if iPad dock is just pulled up but doesn't cause the app to become inactive, i.e. going to background mode. In this case, no functions in SceneDelegate will be called and I find it impossible to detect that DragGesture has been interrupted. Any possible solution?

struct ContentView: View {
  @State private var offset = CGSize.zero

  var body: some View {
    ZStack {
      Rectangle()
        .fill(Color.clear)
        .frame(width: 100, height: 100)
        .border(Color.black, width: 5)

      Circle()
        .fill(Color.red)
        .frame(width: 90, height: 90)
        .offset(offset)
        .gesture(
          DragGesture()
            .onChanged() { self.offset = $0.translation }
            .onEnded() { _ in self.offset = CGSize.zero })
    }
  }
}

Image 1

Image 2

like image 888
appthumb Avatar asked Feb 16 '20 21:02

appthumb


1 Answers

Try with GestureState as follows. It is temporary, by default, and when ended is reset to initial value by design.

struct ContentView: View {
  @GestureState private var offset = CGSize.zero

  var body: some View {
    ZStack {
      Rectangle()
        .fill(Color.clear)
        .frame(width: 100, height: 100)
        .border(Color.black, width: 5)

      Circle()
        .fill(Color.red)
        .frame(width: 90, height: 90)
        .offset(offset)
        .gesture(
          DragGesture()
            .updating($offset) { (value, gestureState, transaction) in
                gestureState = CGSize(width: value.location.x - value.startLocation.x, height: value.location.y - value.startLocation.y)
            })
    }
  }
}
like image 53
Asperi Avatar answered Nov 12 '22 06:11

Asperi