Skip to content

Commit ebf1b8a

Browse files
committed
fix: solved the bug where maxScrollDistancePerSwipe could not work.
1 parent 687ee56 commit ebf1b8a

File tree

1 file changed

+73
-10
lines changed

1 file changed

+73
-10
lines changed

src/ScrollViewGesture.tsx

Lines changed: 73 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { PropsWithChildren } from "react";
2-
import React from "react";
2+
import React, { useCallback, useMemo } from "react";
33
import type { StyleProp, ViewStyle } from "react-native";
44
import type { GestureStateChangeEvent, PanGestureHandlerEventPayload } from "react-native-gesture-handler";
55
import {
@@ -70,6 +70,7 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
7070
const scrollEndTranslation = useSharedValue(0);
7171
const scrollEndVelocity = useSharedValue(0);
7272
const containerRef = useAnimatedRef<Animated.View>();
73+
const maxScrollDistancePerSwipeIsSet = typeof maxScrollDistancePerSwipe === "number";
7374

7475
// Get the limit of the scroll.
7576
const getLimit = React.useCallback(() => {
@@ -121,7 +122,7 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
121122
let finalTranslation: number = withDecay({ velocity, deceleration: 0.999 });
122123

123124
// If the distance of the swipe exceeds the max scroll distance, keep the view at the current position
124-
if (typeof maxScrollDistancePerSwipe === "number" && Math.abs(scrollEndTranslation.value) > maxScrollDistancePerSwipe) {
125+
if (maxScrollDistancePerSwipeIsSet && Math.abs(scrollEndTranslation.value) > maxScrollDistancePerSwipe) {
125126
finalTranslation = origin;
126127
}
127128
else {
@@ -178,6 +179,7 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
178179
scrollEndVelocity.value,
179180
maxScrollDistancePerSwipe,
180181
scrollEndTranslation.value,
182+
maxScrollDistancePerSwipeIsSet,
181183
],
182184
);
183185

@@ -245,7 +247,19 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
245247
[pagingEnabled, resetBoundary],
246248
);
247249

248-
const onGestureBegin = () => {
250+
function withProcessTranslation(translation: number) {
251+
"worklet";
252+
253+
if (!infinite && !overscrollEnabled) {
254+
const limit = getLimit();
255+
const sign = Math.sign(translation);
256+
return sign * Math.max(0, Math.min(limit, Math.abs(translation)));
257+
}
258+
259+
return translation;
260+
}
261+
262+
const onGestureBegin = useCallback(() => {
249263
"worklet";
250264

251265
touching.value = true;
@@ -257,8 +271,21 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
257271
max.value = getLimit();
258272

259273
panOffset.value = translation.value;
260-
};
261-
const onGestureUpdate = (e: PanGestureHandlerEventPayload) => {
274+
}, [
275+
max,
276+
size,
277+
maxPage,
278+
infinite,
279+
touching,
280+
panOffset,
281+
validStart,
282+
translation,
283+
overscrollEnabled,
284+
getLimit,
285+
onScrollBegin,
286+
]);
287+
288+
const onGestureUpdate = useCallback((e: PanGestureHandlerEventPayload) => {
262289
"worklet";
263290

264291
if (validStart.value) {
@@ -282,8 +309,18 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
282309

283310
const translationValue = panOffset.value + panTranslation;
284311
translation.value = translationValue;
285-
};
286-
const onGestureFinish = (e: GestureStateChangeEvent<PanGestureHandlerEventPayload>) => {
312+
}, [
313+
isHorizontal,
314+
max,
315+
panOffset,
316+
infinite,
317+
overscrollEnabled,
318+
translation,
319+
validStart,
320+
touching,
321+
]);
322+
323+
const onGestureFinish = useCallback((e: GestureStateChangeEvent<PanGestureHandlerEventPayload>) => {
287324
"worklet";
288325

289326
const { velocityX, velocityY, translationX, translationY } = e;
@@ -294,13 +331,39 @@ const IScrollViewGesture: React.FC<PropsWithChildren<Props>> = (props) => {
294331
? translationX
295332
: translationY;
296333

297-
endWithSpring(onScrollEnd);
334+
const totalTranslation = scrollEndVelocity.value + scrollEndTranslation.value;
335+
336+
if (maxScrollDistancePerSwipeIsSet && Math.abs(totalTranslation) > maxScrollDistancePerSwipe) {
337+
const nextPage = Math.round((panOffset.value + maxScrollDistancePerSwipe * Math.sign(totalTranslation)) / size) * size;
338+
translation.value = withSpring(withProcessTranslation(nextPage), onScrollEnd);
339+
}
340+
else {
341+
endWithSpring(onScrollEnd);
342+
}
298343

299344
if (!infinite)
300345
touching.value = false;
301-
};
346+
}, [
347+
size,
348+
infinite,
349+
touching,
350+
panOffset,
351+
translation,
352+
isHorizontal,
353+
scrollEndVelocity,
354+
scrollEndTranslation,
355+
maxScrollDistancePerSwipeIsSet,
356+
maxScrollDistancePerSwipe,
357+
endWithSpring,
358+
withSpring,
359+
onScrollEnd,
360+
]);
302361

303-
const gesture = Gesture.Pan().onBegin(onGestureBegin).onUpdate(onGestureUpdate).onEnd(onGestureFinish);
362+
const gesture = useMemo(() => Gesture.Pan().onBegin(onGestureBegin).onUpdate(onGestureUpdate).onEnd(onGestureFinish), [
363+
onGestureBegin,
364+
onGestureUpdate,
365+
onGestureFinish,
366+
]);
304367
const GestureContainer = enabled ? GestureDetector : React.Fragment;
305368

306369
return (

0 commit comments

Comments
 (0)