feat(ios): add swipeToSeek#750
Conversation
|
Seeking review from @BartoszKlonowski I think, whenever you have a moment? 🙏🏻🙇🏻♂️ |
|
hi @draggie i notice you're in the middle of a rewrite of the library. Are you considering open issues like this in that or just working on parity with existing features? |
|
Hello @sterlingwes, thanks for reaching out! |
|
awesome thanks @BartoszKlonowski for the update 🙏🏻 sounds good |
BartoszKlonowski
left a comment
There was a problem hiding this comment.
I have some simple comments/questions, but I "request changes" because I think that the swipeToSeek should be hardcoded to true.
The reason is that in previous versions of iOS platform this is how Slider was working, and there was no option to turn off the behavior of being able to swipe from any position. I would like to keep it that way, instead of introducing new prop that will be instantly turned on by (I assume) majority of consumers.
@sterlingwes Are you OK adjusting to that idea or do you have a strong reasoning behind the current approach?
Let me know :)
| RNCSlider *slider; | ||
| UIImage *_image; | ||
| BOOL _isSliding; | ||
| BOOL _swipeGestureEnabled; |
There was a problem hiding this comment.
@sterlingwes Can you elaborate on why we need this private variable?
From what I see it's only used once in the whole runtime to set the gesture recognizer. But is this required?
If we could make the swipeToSeek being true by default, we wouldn't need this additional var check.
| CGPoint location = [gesture locationInView:slider]; | ||
|
|
||
| switch (gesture.state) { | ||
|
|
| - (float)calculateSliderValueFromLocation:(CGPoint)point { | ||
| CGFloat sliderWidth = slider.bounds.size.width; | ||
|
|
||
| if (sliderWidth <= 0) { |
There was a problem hiding this comment.
When such case is possible?
|
|
||
| case UIGestureRecognizerStateEnded: | ||
| case UIGestureRecognizerStateCancelled: | ||
| case UIGestureRecognizerStateFailed: { |
There was a problem hiding this comment.
Don't we want to avoid sending an event if the state is failed?
What will be the value sent with this event? Will it still be updated despite being failed, or will we send duplicated position?
Let's handle the UIGestureRecognizerStateFailed separately, I'm fine having it doing nothing, unless you have some other ideas.
Summary:
I noticed on iOS that the slider does not behave as it does on Android when you make a swipe gesture on the track bar away from the thumb. On Android, the thumb snaps to the gesture point of the swipe and follows it along until the gesture ends. This feels more fluid and native, and allows for the user to be less precise in pressing the thumb but still find the precise value they want.
tapToSeekdoesn't allow for this since it expects a short press, but if a user is trying to grab the thumb and misses, nothing happens because the gesture is a swipe/pan.I opted to conditionally add a pan gesture recognizer on iOS (which allows for swiping continuously in both directions) to achieve this based on an opt-in boolean prop
swipeToSeek. This works fine alongside the existing tap recognizer for when tapToSeek is also enabled.Test Plan:
In the video below I'm demonstrating how it behaves relative to the tapToSeek behaviour with both steps defined and not. I also show that for sliders where the swipeToSeek prop is not set to true, it won't respond to those swipe gestures.
Screen.Recording.2025-12-14.at.8.56.19.PM.mov
I also verified the event handlers work the same by temporarily toggling the prop in these prop examples:
onSlidingStart / onSlidingComplete BEFORE (no swipeToSeek)
Screen.Recording.2025-12-14.at.9.08.14.PM.mov
onSlidingStart / onSlidingComplete AFTER (with swipeToSeek)
Screen.Recording.2025-12-14.at.9.13.58.PM.mov