1

In my app, I drag a View horizontally to set a position of a model object. I can also drag it downward and release it to delete the model object. When it has been dragged downward far enough, I indicate the potential for deletion by changing its appearance. The problem is that this change interrupts the DragGesture. I don't understand why this happens.

The example code below demonstrates the problem. You can drag the light blue box side to side. If you pull down, it and it turns to the "rays" system image, but the drag dies.

The DragGesture is applied to the ZStack with a size of 50x50. The ZStack should continue to exist across that state change, no? Why is the drag gesture dying?

struct ContentView: View {
    var body: some View {
        ZStack {
            DraggableThing()
        }.frame(width: 300, height: 300)
         .border(Color.black, width: 1)
    }
}

struct DraggableThing: View {

    @State private var willDeleteIfDropped = false
    @State private var xPosition: CGFloat = 150

    var body: some View {
        //Rectangle()
        //    .fill(willDeleteIfDropped ? Color.red : Color.blue.opacity(0.3))
        ZStack {
            if willDeleteIfDropped {
                Image(systemName: "rays")
            } else {
                Rectangle().fill(Color.blue.opacity(0.3))
            }
        }
            .frame(width: 50, height: 50)
            .position(x: xPosition, y: 150)
            .gesture(DragGesture()
                .onChanged { val in
                    print("drag changed \(val.translation)")
                    self.xPosition = 150 + val.translation.width
                    self.willDeleteIfDropped = (val.translation.height > 25)
                }
                .onEnded { val in
                    print("drag ended")
                    self.xPosition = 150
                }
            )
    }
}
Rob N
  • 15,024
  • 17
  • 92
  • 165

1 Answers1

1

You need to keep content, which originally captured gesture. So your goal can be achieved with the following changes:

ZStack {
    Rectangle().fill(Color.blue.opacity(willDeleteIfDropped ? 0.0 : 0.3))
    if willDeleteIfDropped {
        Image(systemName: "rays")
    }
}
Asperi
  • 228,894
  • 20
  • 464
  • 690
  • I can confirm this works for me. It seems like non-ideal behavior from SwiftUI. ZStack is a View, and I attached a gesture to it. It seems like it breaks the abstraction if I have to think about what's inside the view to this degree. – Rob N Feb 20 '20 at 16:28