@@ -52,6 +52,7 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
5252 enabled,
5353 dataLength,
5454 overscrollEnabled,
55+ maxScrollDistancePerSwipe,
5556 } ,
5657 } = React . useContext ( CTX ) ;
5758
@@ -122,33 +123,39 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
122123 // Default to scroll in the direction of the slide (with deceleration)
123124 let finalTranslation : number = withDecay ( { velocity, deceleration : 0.999 } ) ;
124125
126+ // If the distance of the swipe exceeds the max scroll distance, keep the view at the current position
127+ if ( typeof maxScrollDistancePerSwipe === "number" && Math . abs ( scrollEndTranslation . value ) > maxScrollDistancePerSwipe ) {
128+ finalTranslation = origin ;
129+ }
130+ else {
125131 /**
126132 * The page size is the same as the item size.
127133 * If direction is vertical, the page size is the height of the item.
128134 * If direction is horizontal, the page size is the width of the item.
129- *
130- * `page size` equals to `size` variable.
131- * */
132- if ( pagingEnabled ) {
133- // distance with direction
134- const offset = - ( scrollEndTranslation . value >= 0 ? 1 : - 1 ) ; // 1 or -1
135- const computed = offset < 0 ? Math . ceil : Math . floor ;
136- const page = computed ( - translation . value / size ) ;
137-
138- if ( infinite ) {
139- const finalPage = page + offset ;
140- finalTranslation = withSpring ( withProcessTranslation ( - finalPage * size ) , onFinished ) ;
141- }
142- else {
143- const finalPage = Math . min ( maxPage - 1 , Math . max ( 0 , page + offset ) ) ;
144- finalTranslation = withSpring ( withProcessTranslation ( - finalPage * size ) , onFinished ) ;
135+ *
136+ * `page size` equals to `size` variable.
137+ * */
138+ if ( pagingEnabled ) {
139+ // distance with direction
140+ const offset = - ( scrollEndTranslation . value >= 0 ? 1 : - 1 ) ; // 1 or -1
141+ const computed = offset < 0 ? Math . ceil : Math . floor ;
142+ const page = computed ( - translation . value / size ) ;
143+
144+ if ( infinite ) {
145+ const finalPage = page + offset ;
146+ finalTranslation = withSpring ( withProcessTranslation ( - finalPage * size ) , onFinished ) ;
147+ }
148+ else {
149+ const finalPage = Math . min ( maxPage - 1 , Math . max ( 0 , page + offset ) ) ;
150+ finalTranslation = withSpring ( withProcessTranslation ( - finalPage * size ) , onFinished ) ;
151+ }
145152 }
146- }
147153
148- if ( ! pagingEnabled && snapEnabled ) {
149- // scroll to the nearest item
150- const nextPage = Math . round ( ( origin + velocity * 0.4 ) / size ) * size ;
151- finalTranslation = withSpring ( withProcessTranslation ( nextPage ) , onFinished ) ;
154+ if ( ! pagingEnabled && snapEnabled ) {
155+ // scroll to the nearest item
156+ const nextPage = Math . round ( ( origin + velocity * 0.4 ) / size ) * size ;
157+ finalTranslation = withSpring ( withProcessTranslation ( nextPage ) , onFinished ) ;
158+ }
152159 }
153160
154161 translation . value = finalTranslation ;
@@ -164,15 +171,16 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
164171 }
165172 } ,
166173 [
167- translation ,
168- scrollEndVelocity . value ,
169- pagingEnabled ,
174+ withSpring ,
170175 size ,
171- scrollEndTranslation . value ,
176+ maxPage ,
172177 infinite ,
173- withSpring ,
174178 snapEnabled ,
175- maxPage ,
179+ translation ,
180+ pagingEnabled ,
181+ scrollEndVelocity . value ,
182+ maxScrollDistancePerSwipe ,
183+ scrollEndTranslation . value ,
176184 ] ,
177185 ) ;
178186
@@ -240,6 +248,18 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
240248 [ pagingEnabled , resetBoundary ] ,
241249 ) ;
242250
251+ function withProcessTranslation ( translation : number ) {
252+ "worklet" ;
253+
254+ if ( ! infinite && ! overscrollEnabled ) {
255+ const limit = getLimit ( ) ;
256+ const sign = Math . sign ( translation ) ;
257+ return sign * Math . max ( 0 , Math . min ( limit , Math . abs ( translation ) ) ) ;
258+ }
259+
260+ return translation ;
261+ }
262+
243263 const panGestureEventHandler = useAnimatedGestureHandler <
244264 PanGestureHandlerGestureEvent ,
245265 GestureContext
@@ -262,10 +282,19 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
262282 cancelAnimation ( translation ) ;
263283 }
264284 touching . value = true ;
265- const { translationX, translationY } = e ;
266- const panTranslation = isHorizontal . value
267- ? translationX
268- : translationY ;
285+ let { translationX, translationY } = e ;
286+
287+ const totalTranslation = isHorizontal . value ? translationX : translationY ;
288+
289+ if ( typeof maxScrollDistancePerSwipe === "number" && Math . abs ( totalTranslation ) > maxScrollDistancePerSwipe ) {
290+ const overSwipe = Math . abs ( totalTranslation ) - maxScrollDistancePerSwipe ;
291+ const dampedTranslation = maxScrollDistancePerSwipe + overSwipe * 0.5 ;
292+
293+ translationX = isHorizontal . value ? dampedTranslation * Math . sign ( translationX ) : translationX ;
294+ translationY = ! isHorizontal . value ? dampedTranslation * Math . sign ( translationY ) : translationY ;
295+ }
296+
297+ const panTranslation = isHorizontal . value ? translationX : translationY ;
269298 if ( ! infinite ) {
270299 if ( ( translation . value > 0 || translation . value < - ctx . max ) ) {
271300 const boundary = translation . value > 0 ? 0 : - ctx . max ;
@@ -277,9 +306,10 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
277306 }
278307
279308 const translationValue = ctx . panOffset + panTranslation ;
309+
280310 translation . value = translationValue ;
281311 } ,
282- onEnd : ( e ) => {
312+ onEnd : ( e , ctx ) => {
283313 const { velocityX, velocityY, translationX, translationY } = e ;
284314 scrollEndVelocity . value = isHorizontal . value
285315 ? velocityX
@@ -288,7 +318,15 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
288318 ? translationX
289319 : translationY ;
290320
291- endWithSpring ( onScrollEnd ) ;
321+ const totalTranslation = isHorizontal . value ? translationX : translationY ;
322+
323+ if ( typeof maxScrollDistancePerSwipe === "number" && Math . abs ( totalTranslation ) > maxScrollDistancePerSwipe ) {
324+ const nextPage = Math . round ( ( ctx . panOffset + maxScrollDistancePerSwipe * Math . sign ( totalTranslation ) ) / size ) * size ;
325+ translation . value = withSpring ( withProcessTranslation ( nextPage ) , onScrollEnd ) ;
326+ }
327+ else {
328+ endWithSpring ( onScrollEnd ) ;
329+ }
292330
293331 if ( ! infinite )
294332 touching . value = false ;
0 commit comments