superpuccio
superpuccio

Reputation: 12972

SwiftUI: VStack/HStack/ZStack drag gesture not working

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.

Upvotes: 20

Views: 9498

Answers (2)

Asperi
Asperi

Reputation: 257663

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
        }
    )
}

Upvotes: 9

Anton
Anton

Reputation: 3257

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. :)

Upvotes: 50

Related Questions