So I have a ScrollView holding a set of views:
ScrollView {
ForEach(cities) { city in
NavigationLink(destination: ...) {
I finally found a solution that seems to work with me. I have found Button to be magical creatures. They propagate events properly, and keep on working even if you are inside a ScrollView or a List.
Now, you will say
Yeah, but Michel, I don't want a friggin button that taps with some effects, I want to long-press something, or drag something.
Fair enough. But you must consider the Button of lore as something that actually makes everything underneath its label: as actually working correctly, if you know how to do things! Because the Button will actually try to behave, and delegate its gestures to controls underneath if they actually implement onTapGesture, so you can get a toggle or an info.circle button you can tap inside. In other words, All gestures that appears after the onTapGesture {} (but not the ones before) will work.
As a complex code example, what you must have is as follow:
ScrollView {
Button(action: {}) { // Makes everything behave in the "label:"
content // Notice this uses the ViewModifier ways ... hint hint
.onTapGesture {} // This view overrides the Button
.gesture(LongPressGesture(minimumDuration: 0.01)
.sequenced(before: DragGesture(coordinateSpace: .global))
.updating(self.$dragState) { ...
The example uses a complex gesture because I wanted to show they do work, as long as that elusive Button/onTapGesture combo are there.
Now you will notice this is not totally perfect, the long press is actually long-pressed too by the button before it delegates its long press to yours (so that example will have more than 0.01 second of long press). Also, you must have a ButtonStyle if you wish to remove the pressed effects. In other words, YMMV, a lot of testing, but for my own usage, this is the closest I've been able to make an actual long press / drag work in a List of items.