7
votes

I don't understand why the DragGesture doesn't work on VStack/HStack/ZStack. Consider the following simple example:

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

    var body: some View {
        VStack {
            Text("Hello World!")
        }
        .frame(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height)
        .edgesIgnoringSafeArea(.all)
        .offset(y: offset.height)
        .gesture(DragGesture()
            .onChanged { val in
                self.offset = val.translation
            }
            .onEnded { val in
                self.offset = .zero
            }
        )
    }
}

I'd like the whole view to move up and down based on the offset var (changed by the drag gesture). But even if I write the .gesture modifier on the VStack and even if the VStack is full screen (thanks to the .frame modifier) the drag gesture won't work on the VStack. The gesture works only if I drag the "Hello world" text, but it's unresponsive if I drag outside the Text (but still inside the full screen VStack). Any ideas? Thanks.

2

2 Answers

16
votes

Actually, there's a SwiftUI feature meant to address just that issue with no need for a background.

Simply place .contentShape(Rectangle()) just before your gesture modifier and it will respond to the whole enclosing rectangle. :)

6
votes

Your container is transparent. Transparent thing does not handle events. So, add some background, like in demo below and all works.

var body: some View {
    VStack {
        Text("Hello World!")
    }
    .frame(width: UIScreen.main.bounds.size.width, height: UIScreen.main.bounds.size.height)
    .edgesIgnoringSafeArea(.all)
    .background(Color.white)
    .offset(y: offset.height)
    .gesture(DragGesture()
        .onChanged { val in
            self.offset = val.translation
        }
        .onEnded { val in
            self.offset = .zero
        }
    )
}