danielsaidi / SwiftUIKit

SwiftUIKit is a Swift SDK that adds extra functionality to Swift & SwiftUI.
MIT License
1.42k stars 56 forks source link

Ability for GestureButton to gracefully prioritise handling between a tap and long press action #15

Open bardigolriz opened 1 year ago

bardigolriz commented 1 year ago

I have a GestureButton that I have events for when the user taps as well as long presses (with a minimum delay).

I can’t depend on plain SwiftUI gesture modifiers for this because when the two are chained together, the long press minimum duration set appears to be ignored.

With GestureButton, I am trying to use releaseInsideAction combined with longPressAction with a longPressDelay of 0.1.

When I tap on the button, the releaseInsideAction is called correctly.

When I long press on the button, the longPressAction after the correct delay is called correctly. However, it also then proceeds to call the releaseInsideAction too, which isn’t what I want or expected.

To workaround this, I have added a new @State variable:

private var isLongPressed: Bool = false

Inside tryTriggerLongPressAfterDelay(), after its action() call, I flag it to be true:

        DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
            guard self.longPressDate == date else { return }
            action()
            isLongPressed = true
        }

Finally, in tryHandleRelease(), I check whether isLongPressed is true to determine whether to proceed with its associated action:

        if !isLongPressed {
            if geo.contains(value.location) {
                releaseInsideAction?()
            } else {
                releaseOutsideAction?()
            }
        }
        else {
            isLongPressed = false
        }
        endAction?()

In my tests, this seems to work really well without any issues. Can’t see where it could possibly trip up! Thank you so much for implementing such a versatile button that helps workaround SwiftUI limitations.

danielsaidi commented 1 year ago

Thank you @bardigolriz

Although I aimed for GestureButton to be pretty straightforward, I can see the use case where you would not want to trigger the release action after the long press.

I will try to find time to add this to the two buttons 👍