0

I'm trying to use the DragGesture for my side menu. Currently, the DragGesture is using the entire screen, and I'd like to use it only from the left to right as shown in the screenshot (gray area):

My code snippet:

@State var width = UIScreen.main.bounds.width - 65
@State var x = -UIScreen.main.bounds.width + 65

var body: some View {
    
    ZStack(alignment: Alignment(horizontal: .leading, vertical: .center)) {
        HomePage(x: $x)
        SlideMenu()
            .shadow(color: Color.black.opacity(x == 0 ? 0.2 : 0), radius: 5, x: 5, y:0)
            .offset(x: x)
            .background(Color.gray.opacity(x == 0 ? 0.2 : 0).ignoresSafeArea(.all, edges: .vertical).onTapGesture {
                withAnimation {
                    
                    x = -width
                }
            })
    }
    .gesture(DragGesture().onChanged({ (value) in
        withAnimation {
            if value.translation.width > 0 {
                if x < 0 {
                    x = -width + value.translation.width
                }
            }
            else {
                x = value.translation.width
            }
        }
    }).onEnded({ (value) in
        withAnimation {
            if -x < width / 2 {
            x = 0
            }
            else {
                x = -width
            }
        }
    }))
}
koen
  • 5,383
  • 7
  • 50
  • 89
  • 2
    Hello, did my answer solve your problem? If so, please accept it. [What should I do when someone answers my question?](https://stackoverflow.com/help/someone-answers) – Phil Dukhov Sep 05 '21 at 11:28

1 Answers1

1

You can check gesture startLocation and ignore it, if it's out of your desired rect

struct ContentView: View {
    @State var width = UIScreen.main.bounds.width - 65
    @State var x = -UIScreen.main.bounds.width + 65
    let gestureMaxScreenOffset: CGFloat = 100

    var body: some View {
        ZStack(alignment: Alignment(horizontal: .leading, vertical: .center)) {
            Text("HomePage(x: $x)")
                .onTapGesture {
                    print("hello")
                }
            Text("SlideMenu()")
                .fillMaxSize()
                .shadow(color: Color.black.opacity(x == 0 ? 0.2 : 0), radius: 5, x: 5, y: 0)
                .offset(x: x)
                .background(Color.gray.opacity(x == 0 ? 0.2 : 0).ignoresSafeArea(.all, edges: .vertical).onTapGesture {
                    withAnimation {

                        x = -width
                    }
                })
        }.gesture(DragGesture().onChanged({ (value) in
            withAnimation {
                if value.startLocation.x > gestureMaxScreenOffset {
                    return
                }
                if value.translation.width > 0 {
                    if x < 0 {
                        x = -width + value.translation.width
                    }
                } else {
                    x = value.translation.width
                }
            }
        }).onEnded({ (value) in
            if value.startLocation.x > gestureMaxScreenOffset {
                return
            }
            withAnimation {
                if -x < width / 2 {
                    x = 0
                } else {
                    x = -width
                }
            }
        }))
    }
}
Phil Dukhov
  • 67,741
  • 15
  • 184
  • 220