Using DragGesture to implement touchDown and touchUp interferes with scrolling in ScrollView

Hi there, I'm playing with SwiftUI and trying to implement a scrolling view with buttons that adjust their transform on touchDown and touchUp.

I'm using a DragGesture with a minimum distance of 0 to implement touchDown and touchUp, and finding that it blocks scrolling. My approach might be wrong here, so wondering how to best accomplish what I'm trying to do.

Here's a Playground snippet that reproduces my issue

import SwiftUI
import PlaygroundSupport

public extension View {
    func onTouchDown(
        _ onTouchDown: @escaping () -> Void,
        onTouchUp: @escaping () -> Void) -> some View {
        self.gesture(
            DragGesture(minimumDistance: 0, coordinateSpace: .local)
                .onChanged({ _ in onTouchDown() })
                .onEnded({ _ in onTouchUp()})
        )
    }
}


struct ContentView: View {

    var body: some View {
        GeometryReader { geo in
            ScrollView {
                VStack(spacing: 50) {
                    Rectangle()
                        .frame(width: geo.size.width, height: 100)
                        .onTouchDown({
                            print("touch down")
                        }) {
                            print("touch up")
                    }
                    Rectangle()
                        .frame(width: geo.size.width, height: 100)
                        .onTouchDown({
                            print("touch down")
                        }) {
                            print("touch up")
                    }
                    Rectangle()
                        .frame(width: geo.size.width, height: 100)
                        .onTouchDown({
                            print("touch down")
                        }) {
                            print("touch up")
                    }

                    Rectangle()
                        .frame(width: geo.size.width, height: 100)
                        .onTouchDown({
                            print("touch down")
                        }) {
                            print("touch up")
                    }
                }.offset(y: 100)
            }
        }
    }
}

PlaygroundPage.current.liveView = UIHostingController(
    rootView: ContentView()
)

I'd like for my drag gestures on the subviews as well as the ScrollView's drag to be simultaneously recognized.

1 Like

I’m not sure if it will solve your particular issue or not, but don’t use DragGesture to imitate touchDown. Instead use LongPressGesture with 0 long press duration.

This only seems to fire the onEnded method. How are you supposed to get touch up after touchdown? That seems to be why people used DragGesture instead.

You could add onTap modifier to replicate the touchUp while the long press gesture with zero duration will handle the touchDown event.

That sounds very hacky you may need to post a snippet to show an effective implementation.

What‘s hack about using this over a drag gesture? The is no dragging involved. Abusing a drag gesture would be rather hacky than a combination of a long press gesture and a tap gesture.

Because it is and it doesn't give you the effect that you'd want anyhow. The community seems to have settled on using drag gesture to do touch down touch up events. My recommendation would be to use a @GestureState observer in conjunction with .updating():

DragGesture(minimumDistance: 0)
    .updating($gestureState) { _, state, _ in
       state = true
    }

Gesture state automatically goes back to it's previous condition once touch is released so you can use it to execute the code you need like this:

$gestureState ? ifDownDoThis() : ifUpDoThat()

I don‘t want to sound rude but this is logical nonsense. Not every answer created by the community is correct.

Not taken rudely at all. That's correct, in fact the way most were implementing it seemed to be wrong. I'm basing my choice solely off of achieving the desired result. I haven't found a better method for implementing touch down touch up then what I've posted above. If someone presents a better solution I'll post it in a follow up.

1 Like

I‘ll check tomorrow how I‘d implement it. I‘m only at my phone right now.