react-native-reanimated-carousel 3.1.5 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.zh-CN.md +30 -30
- package/lib/commonjs/Carousel.js +1 -1
- package/lib/commonjs/Carousel.js.map +1 -1
- package/lib/commonjs/ScrollViewGesture.js +1 -1
- package/lib/commonjs/ScrollViewGesture.js.map +1 -1
- package/lib/commonjs/hooks/computeNewIndexWhenDataChanges.js +1 -1
- package/lib/commonjs/hooks/computeNewIndexWhenDataChanges.js.map +1 -1
- package/lib/commonjs/hooks/useCarouselController.js +1 -1
- package/lib/commonjs/hooks/useCarouselController.js.map +1 -1
- package/lib/commonjs/hooks/useCommonVariables.js +1 -1
- package/lib/commonjs/hooks/useCommonVariables.js.map +1 -1
- package/lib/commonjs/hooks/useInitProps.js +1 -1
- package/lib/commonjs/hooks/useInitProps.js.map +1 -1
- package/lib/commonjs/hooks/useOffsetX.js +1 -1
- package/lib/commonjs/hooks/useOffsetX.js.map +1 -1
- package/lib/commonjs/hooks/useOnProgressChange.js +1 -1
- package/lib/commonjs/hooks/useOnProgressChange.js.map +1 -1
- package/lib/commonjs/hooks/useVisibleRanges.js +1 -1
- package/lib/commonjs/hooks/useVisibleRanges.js.map +1 -1
- package/lib/commonjs/layouts/BaseLayout.js +1 -1
- package/lib/commonjs/layouts/BaseLayout.js.map +1 -1
- package/lib/commonjs/layouts/ParallaxLayout.js +1 -1
- package/lib/commonjs/layouts/ParallaxLayout.js.map +1 -1
- package/lib/commonjs/layouts/normal.js +1 -1
- package/lib/commonjs/layouts/normal.js.map +1 -1
- package/lib/commonjs/layouts/parallax.js +1 -1
- package/lib/commonjs/layouts/parallax.js.map +1 -1
- package/lib/commonjs/layouts/stack.js +1 -1
- package/lib/commonjs/layouts/stack.js.map +1 -1
- package/lib/commonjs/utils/computedWithAutoFillData.js +1 -1
- package/lib/commonjs/utils/computedWithAutoFillData.js.map +1 -1
- package/lib/commonjs/utils/dealWithAnimation.js +1 -1
- package/lib/commonjs/utils/dealWithAnimation.js.map +1 -1
- package/lib/commonjs/utils/handlerOffsetDirection.js +1 -1
- package/lib/commonjs/utils/log.js +1 -1
- package/lib/module/ScrollViewGesture.js +79 -37
- package/lib/module/ScrollViewGesture.js.map +1 -1
- package/lib/module/hooks/useInitProps.js +5 -2
- package/lib/module/hooks/useInitProps.js.map +1 -1
- package/lib/module/utils/dealWithAnimation.js +2 -6
- package/lib/module/utils/dealWithAnimation.js.map +1 -1
- package/lib/typescript/types.d.ts +10 -5
- package/package.json +8 -4
- package/src/ScrollViewGesture.tsx +80 -39
- package/src/hooks/useInitProps.ts +5 -2
- package/src/types.ts +12 -5
- package/src/utils/dealWithAnimation.ts +6 -10
|
@@ -6,9 +6,11 @@ import {
|
|
|
6
6
|
} from "react-native-gesture-handler";
|
|
7
7
|
import Animated, {
|
|
8
8
|
cancelAnimation,
|
|
9
|
+
measure,
|
|
9
10
|
runOnJS,
|
|
10
11
|
useAnimatedGestureHandler,
|
|
11
12
|
useAnimatedReaction,
|
|
13
|
+
useAnimatedRef,
|
|
12
14
|
useDerivedValue,
|
|
13
15
|
useSharedValue,
|
|
14
16
|
withDecay,
|
|
@@ -49,6 +51,7 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
|
|
|
49
51
|
withAnimation,
|
|
50
52
|
enabled,
|
|
51
53
|
dataLength,
|
|
54
|
+
overscrollEnabled,
|
|
52
55
|
},
|
|
53
56
|
} = React.useContext(CTX);
|
|
54
57
|
|
|
@@ -68,8 +71,27 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
|
|
|
68
71
|
const touching = useSharedValue(false);
|
|
69
72
|
const scrollEndTranslation = useSharedValue(0);
|
|
70
73
|
const scrollEndVelocity = useSharedValue(0);
|
|
74
|
+
const containerRef = useAnimatedRef<Animated.View>();
|
|
71
75
|
|
|
72
|
-
|
|
76
|
+
// Get the limit of the scroll.
|
|
77
|
+
const getLimit = React.useCallback(() => {
|
|
78
|
+
"worklet";
|
|
79
|
+
|
|
80
|
+
if (!infinite && !overscrollEnabled) {
|
|
81
|
+
const { width: containerWidth = 0 } = measure(containerRef);
|
|
82
|
+
|
|
83
|
+
// If the item's total width is less than the container's width, then there is no need to scroll.
|
|
84
|
+
if (dataLength * size < containerWidth)
|
|
85
|
+
return 0;
|
|
86
|
+
|
|
87
|
+
// Disable the "overscroll" effect
|
|
88
|
+
return dataLength * size - containerWidth;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return dataLength * size;
|
|
92
|
+
}, [infinite, size, dataLength, overscrollEnabled]);
|
|
93
|
+
|
|
94
|
+
const withSpring = React.useCallback(
|
|
73
95
|
(toValue: number, onFinished?: () => void) => {
|
|
74
96
|
"worklet";
|
|
75
97
|
const defaultWithAnimation: WithTimingAnimation = {
|
|
@@ -97,34 +119,49 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
|
|
|
97
119
|
"worklet";
|
|
98
120
|
const origin = translation.value;
|
|
99
121
|
const velocity = scrollEndVelocity.value;
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
122
|
+
// Default to scroll in the direction of the slide (with deceleration)
|
|
123
|
+
let finalTranslation: number = withDecay({ velocity, deceleration: 0.999 });
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* The page size is the same as the item size.
|
|
127
|
+
* If direction is vertical, the page size is the height of the item.
|
|
128
|
+
* 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);
|
|
111
145
|
}
|
|
112
|
-
translation.value = withDecay({
|
|
113
|
-
velocity,
|
|
114
|
-
deceleration: 0.999,
|
|
115
|
-
});
|
|
116
|
-
return;
|
|
117
146
|
}
|
|
118
147
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
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);
|
|
152
|
+
}
|
|
123
153
|
|
|
124
|
-
|
|
125
|
-
|
|
154
|
+
translation.value = finalTranslation;
|
|
155
|
+
|
|
156
|
+
function withProcessTranslation(translation: number) {
|
|
157
|
+
if (!infinite && !overscrollEnabled) {
|
|
158
|
+
const limit = getLimit();
|
|
159
|
+
const sign = Math.sign(translation);
|
|
160
|
+
return sign * Math.max(0, Math.min(limit, Math.abs(translation)));
|
|
161
|
+
}
|
|
126
162
|
|
|
127
|
-
|
|
163
|
+
return translation;
|
|
164
|
+
}
|
|
128
165
|
},
|
|
129
166
|
[
|
|
130
167
|
translation,
|
|
@@ -133,7 +170,7 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
|
|
|
133
170
|
size,
|
|
134
171
|
scrollEndTranslation.value,
|
|
135
172
|
infinite,
|
|
136
|
-
|
|
173
|
+
withSpring,
|
|
137
174
|
snapEnabled,
|
|
138
175
|
maxPage,
|
|
139
176
|
],
|
|
@@ -170,7 +207,7 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
|
|
|
170
207
|
return;
|
|
171
208
|
}
|
|
172
209
|
if (!infinite) {
|
|
173
|
-
translation.value =
|
|
210
|
+
translation.value = withSpring(0);
|
|
174
211
|
return;
|
|
175
212
|
}
|
|
176
213
|
}
|
|
@@ -181,7 +218,7 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
|
|
|
181
218
|
return;
|
|
182
219
|
}
|
|
183
220
|
if (!infinite)
|
|
184
|
-
translation.value =
|
|
221
|
+
translation.value = withSpring(-((maxPage - 1) * size));
|
|
185
222
|
}
|
|
186
223
|
}, [
|
|
187
224
|
touching.value,
|
|
@@ -191,7 +228,7 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
|
|
|
191
228
|
scrollEndTranslation.value,
|
|
192
229
|
infinite,
|
|
193
230
|
activeDecay,
|
|
194
|
-
|
|
231
|
+
withSpring,
|
|
195
232
|
]);
|
|
196
233
|
|
|
197
234
|
useAnimatedReaction(
|
|
@@ -212,7 +249,11 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
|
|
|
212
249
|
touching.value = true;
|
|
213
250
|
ctx.validStart = true;
|
|
214
251
|
onScrollBegin && runOnJS(onScrollBegin)();
|
|
252
|
+
|
|
215
253
|
ctx.max = (maxPage - 1) * size;
|
|
254
|
+
if (!infinite && !overscrollEnabled)
|
|
255
|
+
ctx.max = getLimit();
|
|
256
|
+
|
|
216
257
|
ctx.panOffset = translation.value;
|
|
217
258
|
},
|
|
218
259
|
onActive: (e, ctx) => {
|
|
@@ -225,19 +266,18 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
|
|
|
225
266
|
const panTranslation = isHorizontal.value
|
|
226
267
|
? translationX
|
|
227
268
|
: translationY;
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
translation.value = boundary + dynamic * 0.5;
|
|
237
|
-
return;
|
|
269
|
+
if (!infinite) {
|
|
270
|
+
if ((translation.value > 0 || translation.value < -ctx.max)) {
|
|
271
|
+
const boundary = translation.value > 0 ? 0 : -ctx.max;
|
|
272
|
+
const fixed = boundary - ctx.panOffset;
|
|
273
|
+
const dynamic = panTranslation - fixed;
|
|
274
|
+
translation.value = boundary + dynamic * 0.5;
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
238
277
|
}
|
|
239
278
|
|
|
240
|
-
|
|
279
|
+
const translationValue = ctx.panOffset + panTranslation;
|
|
280
|
+
translation.value = translationValue;
|
|
241
281
|
},
|
|
242
282
|
onEnd: (e) => {
|
|
243
283
|
const { velocityX, velocityY, translationX, translationY } = e;
|
|
@@ -273,6 +313,7 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
|
|
|
273
313
|
onGestureEvent={panGestureEventHandler}
|
|
274
314
|
>
|
|
275
315
|
<Animated.View
|
|
316
|
+
ref={containerRef}
|
|
276
317
|
testID={testID}
|
|
277
318
|
style={style}
|
|
278
319
|
onTouchStart={onTouchBegin}
|
|
@@ -31,13 +31,15 @@ export function useInitProps<T>(
|
|
|
31
31
|
defaultIndex = 0,
|
|
32
32
|
data: rawData = [],
|
|
33
33
|
loop = true,
|
|
34
|
-
enabled = true,
|
|
35
34
|
autoPlayInterval: _autoPlayInterval = 1000,
|
|
36
35
|
scrollAnimationDuration = 500,
|
|
37
36
|
style = {},
|
|
38
37
|
panGestureHandlerProps = {},
|
|
39
|
-
pagingEnabled = true,
|
|
40
38
|
autoFillData = true,
|
|
39
|
+
// switchers
|
|
40
|
+
enabled = true,
|
|
41
|
+
pagingEnabled = true,
|
|
42
|
+
overscrollEnabled = true,
|
|
41
43
|
snapEnabled = props.enableSnap ?? true,
|
|
42
44
|
width: _width,
|
|
43
45
|
height: _height,
|
|
@@ -89,6 +91,7 @@ export function useInitProps<T>(
|
|
|
89
91
|
panGestureHandlerProps,
|
|
90
92
|
pagingEnabled,
|
|
91
93
|
snapEnabled,
|
|
94
|
+
overscrollEnabled,
|
|
92
95
|
width,
|
|
93
96
|
height,
|
|
94
97
|
};
|
package/src/types.ts
CHANGED
|
@@ -132,15 +132,14 @@ export type TCarouselProps<T = any> = {
|
|
|
132
132
|
/**
|
|
133
133
|
* If enabled, releasing the touch will scroll to the nearest item.
|
|
134
134
|
* valid when pagingEnabled=false
|
|
135
|
-
* @
|
|
135
|
+
* @default true
|
|
136
136
|
*/
|
|
137
|
-
|
|
137
|
+
snapEnabled?: boolean
|
|
138
138
|
/**
|
|
139
|
-
* If enabled,
|
|
140
|
-
* valid when pagingEnabled=false
|
|
139
|
+
* If enabled, items will scroll to the first placement when scrolling past the edge rather than closing to the last. (previous conditions: loop=false)
|
|
141
140
|
* @default true
|
|
142
141
|
*/
|
|
143
|
-
|
|
142
|
+
overscrollEnabled?: boolean
|
|
144
143
|
/**
|
|
145
144
|
* If false, Carousel will not respond to any gestures.
|
|
146
145
|
* @default true
|
|
@@ -188,6 +187,14 @@ export type TCarouselProps<T = any> = {
|
|
|
188
187
|
offsetProgress: number,
|
|
189
188
|
absoluteProgress: number
|
|
190
189
|
) => void
|
|
190
|
+
|
|
191
|
+
// ============================== deprecated props ==============================
|
|
192
|
+
/**
|
|
193
|
+
* If enabled, releasing the touch will scroll to the nearest item.
|
|
194
|
+
* valid when pagingEnabled=false
|
|
195
|
+
* @deprecated please use snapEnabled instead
|
|
196
|
+
*/
|
|
197
|
+
enableSnap?: boolean
|
|
191
198
|
} & (TParallaxModeProps | TStackModeProps);
|
|
192
199
|
|
|
193
200
|
export interface ICarouselInstance {
|
|
@@ -8,16 +8,12 @@ export function dealWithAnimation(
|
|
|
8
8
|
"worklet";
|
|
9
9
|
switch (withAnimation.type) {
|
|
10
10
|
case "spring":
|
|
11
|
-
return (value, cb) =>
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
);
|
|
15
|
-
};
|
|
11
|
+
return (value, cb) => withSpring(value, withAnimation.config, isFinished =>
|
|
12
|
+
cb(isFinished as boolean),
|
|
13
|
+
);
|
|
16
14
|
case "timing":
|
|
17
|
-
return (value, cb) =>
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
);
|
|
21
|
-
};
|
|
15
|
+
return (value, cb) => withTiming(value, withAnimation.config, isFinished =>
|
|
16
|
+
cb(isFinished as boolean),
|
|
17
|
+
);
|
|
22
18
|
}
|
|
23
19
|
}
|