Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SwiftUI View Jumps on Initial Drag

Tags:

swiftui

I am looking to have a process where a card starts at the bottom of the screen and can be dragged up and down (vertical axis only). I have an issue where on initial drag the card jumps from the bottom of the screen to the top. I have simplified the below to its most minimum to demonstrate the issue. I was thinking it was some sort of coordinate space issue, but changing between local and global doesn't help.

    struct ContentView: View {
        @State private var offset = CGSize(width: 0, height: UIScreen.main.bounds.height * 0.9)
        
        var body: some View {
            GeometryReader { geo in
                Color(.red).edgesIgnoringSafeArea(.all)
                Color(.orange)
                    .clipShape(RoundedRectangle(cornerRadius: 20))
                    .offset(offset)
                    .animation(.spring())
                    .gesture(DragGesture()
                        .onChanged { gesture in
                            offset.height = gesture.translation.height
                        }
                    )
            }
        }
}

Again when the finger is first place at the top of the bottom orange view and the drag gesture begins upwards, the orange view jumps to the top of the red view.

like image 456
C6Silver Avatar asked Nov 01 '25 08:11

C6Silver


1 Answers

You can separate the two different offsets to two different modifiers. First add .offset() with your starting amount. Then add another .offset() that will offset the view from the starting offset.

I also added an .onEnded gesture so that it doesn't lag when starting to drag a 2nd time. You'll probably want to change the .onEnded so that at the end of the gesture the view animates toward a locked position.

struct DragView: View {
    @State private var offsetY: CGFloat = 0
    @State private var lastOffsetY: CGFloat = 0
    
    var body: some View {
        GeometryReader { geo in
            Color(.red)
                .ignoresSafeArea()
            
            
            Color(.orange)
                .clipShape(RoundedRectangle(cornerRadius: 20))
                .offset(y: UIScreen.main.bounds.height * 0.8)
                .offset(y: offsetY)
                .animation(.spring())
                .gesture(DragGesture()
                    .onChanged { gesture in
                        withAnimation(.spring()) {
                            offsetY = lastOffsetY + gesture.translation.height
                        }
                    }
                    .onEnded { _ in
                        lastOffsetY = offsetY
                    }
                )
        }
    }
}
like image 141
nicksarno Avatar answered Nov 04 '25 14:11

nicksarno



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!