Can't touch off the side
I have a slider with a custom thumb
function SliderThumb() {
return (
<View
style={{
backgroundColor: colors.lightColor,
width: 20,
height: 20,
borderRadius: 5,
borderWidth: 2,
borderColor: colors.lightBlue,
}}
/>
);
}
<RangeSlider
onSlidingStart={() => {
setScrollEnabled?.(false);
}}
onSlidingComplete={() => {
setScrollEnabled?.(true);
}}
minimumValue={0}
trackHeight={4}
maximumValue={tracks.length - 1}
step={1}
style={{ paddingHorizontal: 10, height: 40, width: "100%", backgroundColor: "blue" }}
range={value}
thumbSize={100}
onValueChange={setValue}
inboundColor={colors.ToyboxAccentColor}
outboundColor={colors.darkBorder}
crossingAllowed={true}
CustomThumb={(cur) => {
return <SliderThumb key={cur.thumb} />;
}}
CustomMark={(index) => {
const inRange = index.value > value[0] && index.value < value[1];
return (
<View
style={{
height: 12,
backgroundColor: inRange ? colors.ToyboxAccentColor : colors.darkBorder,
width: 2,
}}
/>
);
}}
/>
And its working great overall, but my design has the thumbs go off the edge of the track.
I'm able to increase the vertical touch target by changing the height on the view, but I can't figure out how to extend the touch distance off the side
Touching the left half of the thumb doesn't work and I can't figure out how to extend any of the touch target without also extending the track.
I would expect any touch within the blue part to work for the touch.
Same issue comes up without custom marks/custom thumbs
Is there a prop I am missing, or is this not supported?
I reproduced your test case here
I don't understand why you say that the blue part doesn't respond to your touches. However, I noticed that the cursor is not always a pointer as you could expect. This is because the thumbs have "pointer-events: none" on them. Only the container view responds to touches. However, you can solve this by setting: "cursor: pointer" to the slider style. See my fix in the snack above.
But you can't start the drag on the side there, it doesn't work which is the problem
In the snack, I can move the thumb even if I start pressing on the blue area. Is the probleme related to the onSlidingStart event?
Sorry maybe my case wasn't clear it's if you touch the edge of the slider, on the knob, to the left of the actual line, but still in the blue area. It does accept the click
Sorry maybe my case wasn't clear it's if you touch the edge of the slider, on the knob, to the left of the actual line, but still in the blue area. It doesn't accept the click
Your case is still not clear. Can you try to explain exactly what you are trying to achieve, what is happening instead, and why the provided snack doesn't solve your issue?
So say the blue area is what is between the |
|xxx-----------------xxx|
The slider bar is the -
The slider does not accept touches on the xxx when it should because the thumb goes past the - and into the x area
I have this when I try on the snack. Is it not the expected behavior?
Ah I see the problem, I am using the responsive mode on the browser/apps. So the touch events seem to be broken off the side, but the cursor ones work just fin
And it doesn't work on the mobile versions of that link either updated with more obvious margins: https://snack.expo.dev/nzxuH2ghc
Indeed... Ok, now I think I understand the problem. The issue is that, solving that will be quite troublesome, and I'm not sure I'll have the time soon for such a refacto. I'll write down the steps here if someone wants to give it a try.
The issue is that the ResponderView, in charge of listening to the user touches, is inside the containing view. So, the padding of that view won't respond to touches.
To solve this, we need to:
- Create a ContainerView that wraps the current View from Slider and RangeSlider components
- In that ContainerView we need to access the ref of the ResponderView. If no ref was provided by the user, we need to create one. We need that so we can call
measureLayoutin order to know the offset of the ResponderView relative to the ContainerView. - The ContainerView should receive the onPress, onMove and onRelease listeners, and the responder events from the user. It should create its own set of responder events, just like the ResponderView, except that the eventToValue method should take in consideration the offset of the ResponderView. So, we need to call measureLayout to get that offset. Be careful, if the user provided responder events, they should be called too.
- Remove the code relative to responding to touches from the ResponderView. We don't need it anymore
- Rename ResponderView into SliderView
- Rename ContainerView into ResponderView
Curious your opinion,
Would it also in theory work if we can just apply the padding to the responder view? So if I were to add an extra prop: horizontal padding, and just apply that directly to the responder view, would that work? Or would that break a bunch of other things?
Obviously that's not an ideal solution, but does unblock me.
No, a padding in the responder view would mess up the computation of the positions for the thumb relative to touches. That could be solved, but require an extra work. Instead of spending time in a workaround, it would be better to directly spend that time on the proper solution.
But don't worry, that will be fixed. It's just that, right now, it would be a bit too much for my plate. Anyway, I think that slideOnTap option makes your use case "ok" for users, even if not perfect.
Thanks! I was just probing how complicated it would be. I agree the slideOnTap makes it work great if you know that it works that way
I fixed this in version 8.0.0. Now, the padding area should respond to touches. Please report any bug.