danielsaidi / SwiftUIKit

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

ScrollViewGestureButton remains pressed on fast swipe outside the ScrollView #25

Closed vszakd closed 5 months ago

vszakd commented 1 year ago

Hello, when using the ScrollViewGestureButton preview, a combination of touch and swipe can make the button permanently pressed, even if no button should ever remain pressed without an active touch. No presses on other views will release the button apart from a press on the button itself. Even if the button gets eventually released, the repeating action continues to fire. Only a long press on the button prevents the repeating action from firing.

See video attached: https://github.com/danielsaidi/SwiftUIKit/assets/8497370/2b0655e8-f2f4-41bf-b305-2b4622f16816.

danielsaidi commented 1 year ago

Hi @vszakd

Thank you, that's a great find! Any idea on how to fix it? :)

vszakd commented 1 year ago

Not at the moment, I arrived to your code because my previous solution using a DragGesture had the same problem (and it stole the touch from the ScrollView). Your solution fixes the stealing, but continues to have this other problem.

I invested quite a few time in finding a solution with no luck, and now I am leaning towards creating a UIKit view wrapped in SwiftUI to handle all the gestures.

vszakd commented 1 year ago

Ok, so I might have some news. As we saw, the way the component is written misses the case where the ScrollView cancels the gesture (touch down + scroll as in the video). In that particular case, quite counterintuitively, onEnded is not called by the framework. That might be solvable by not relying solely on @State variables (given that onEnded is not called, they will never get reset, which is what we observe): instead, using a @GestureState (https://developer.apple.com/documentation/swiftui/gesturestate) will make its value reset automatically when the gesture ends or is cancelled.

You can refer to this link for some hints on how to integrate that in the component: https://stackoverflow.com/questions/64424719/swiftui-draggestures-onended-never-called-if-canceled-by-scrollview. In the link, a dragOffset is stored in the @GestureState, but I think in the component's case a simple boolean would suffice.

danielsaidi commented 1 year ago

Thank you so much @vszakd 🙏

danielsaidi commented 9 months ago

@vszakd I've looked at this, and while I can trigger a scroll while the button is pressed in the simulator, I fail to do so on a real device. As soon as I press a button and it starts triggering the repeat action, the scroll view can't scroll.

vszakd commented 9 months ago

I'll try testing on a real device and let you know if that holds true on my test dev as well, in the meantime I reverted to UIKit for scroll related widgets.

On Mon, 4 Dec 2023 at 16:43, Daniel Saidi @.***> wrote:

@vszakd https://github.com/vszakd I've looked at this, and while I can trigger a scroll while the button is pressed in the simulator, I fail to do so on a real device. As soon as I press a button and it starts triggering the repeat action, the scroll view can't scroll.

— Reply to this email directly, view it on GitHub https://github.com/danielsaidi/SwiftUIKit/issues/25#issuecomment-1838914896, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACA2RWQXD5VFGMYRIXIRF4DYHXVQRAVCNFSM6AAAAAA3YXBCP2VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQMZYHEYTIOBZGY . You are receiving this because you were mentioned.Message ID: @.***>

vszakd commented 5 months ago

Everything looks good on physical devices! Thanks @danielsaidi

danielsaidi commented 5 months ago

That's great @vszakd 🙌

So, no need for gesture state?

vszakd commented 3 months ago

Trying extensively your code unchanged on a real iPhone, I could not reproduce the problem, so I would say no need for edits!

danielsaidi commented 3 months ago

Thank you for letting me know!