react-native-reanimated-carousel 2.2.2 → 2.2.5-beta.1
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.md +1 -1
- package/README.zh-CN.md +1 -1
- package/lib/commonjs/Carousel.js +1 -221
- package/lib/commonjs/Carousel.js.map +1 -1
- package/lib/commonjs/LazyView.js +1 -25
- package/lib/commonjs/LazyView.js.map +1 -1
- package/lib/commonjs/ScrollViewGesture.js +1 -217
- package/lib/commonjs/ScrollViewGesture.js.map +1 -1
- package/lib/commonjs/constants/index.js +1 -21
- package/lib/commonjs/constants/index.js.map +1 -1
- package/lib/commonjs/hooks/useAutoPlay.js +1 -61
- package/lib/commonjs/hooks/useAutoPlay.js.map +1 -1
- package/lib/commonjs/hooks/useCarouselController.js +1 -194
- package/lib/commonjs/hooks/useCarouselController.js.map +1 -1
- package/lib/commonjs/hooks/useCommonVariables.js +1 -36
- package/lib/commonjs/hooks/useCommonVariables.js.map +1 -1
- package/lib/commonjs/hooks/useInitProps.js +1 -70
- package/lib/commonjs/hooks/useInitProps.js.map +1 -1
- package/lib/commonjs/hooks/useLayoutConfig.js +1 -39
- package/lib/commonjs/hooks/useLayoutConfig.js.map +1 -1
- package/lib/commonjs/hooks/useOffsetX.js +1 -54
- package/lib/commonjs/hooks/useOffsetX.js.map +1 -1
- package/lib/commonjs/hooks/useOnProgressChange.js +1 -38
- package/lib/commonjs/hooks/useOnProgressChange.js.map +1 -1
- package/lib/commonjs/hooks/usePropsErrorBoundary.js +1 -37
- package/lib/commonjs/hooks/usePropsErrorBoundary.js.map +1 -1
- package/lib/commonjs/hooks/useVisibleRanges.js +1 -42
- package/lib/commonjs/hooks/useVisibleRanges.js.map +1 -1
- package/lib/commonjs/index.js +1 -13
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/layouts/BaseLayout.js +1 -100
- package/lib/commonjs/layouts/BaseLayout.js.map +1 -1
- package/lib/commonjs/layouts/ParallaxLayout.js +1 -82
- package/lib/commonjs/layouts/ParallaxLayout.js.map +1 -1
- package/lib/commonjs/layouts/index.js +1 -20
- package/lib/commonjs/layouts/index.js.map +1 -1
- package/lib/commonjs/layouts/normal.js +1 -27
- package/lib/commonjs/layouts/normal.js.map +1 -1
- package/lib/commonjs/layouts/parallax.js +1 -36
- package/lib/commonjs/layouts/parallax.js.map +1 -1
- package/lib/commonjs/layouts/stack.js +1 -219
- package/lib/commonjs/layouts/stack.js.map +1 -1
- package/lib/commonjs/store/index.js +1 -14
- package/lib/commonjs/store/index.js.map +1 -1
- package/lib/commonjs/types.js +1 -5
- package/lib/commonjs/utils/dealWithAnimation.js +2 -0
- package/lib/commonjs/utils/dealWithAnimation.js.map +1 -0
- package/lib/commonjs/utils/log.js +1 -14
- package/lib/commonjs/utils/log.js.map +1 -1
- package/lib/module/Carousel.js +14 -10
- package/lib/module/Carousel.js.map +1 -1
- package/lib/module/ScrollViewGesture.js +46 -29
- package/lib/module/ScrollViewGesture.js.map +1 -1
- package/lib/module/hooks/useAutoPlay.js +5 -1
- package/lib/module/hooks/useAutoPlay.js.map +1 -1
- package/lib/module/hooks/useCarouselController.js +21 -7
- package/lib/module/hooks/useCarouselController.js.map +1 -1
- package/lib/module/layouts/BaseLayout.js +2 -1
- package/lib/module/layouts/BaseLayout.js.map +1 -1
- package/lib/module/layouts/stack.js.map +1 -1
- package/lib/module/utils/dealWithAnimation.js +17 -0
- package/lib/module/utils/dealWithAnimation.js.map +1 -0
- package/lib/typescript/Carousel.d.ts +3 -4
- package/lib/typescript/ScrollViewGesture.d.ts +3 -1
- package/lib/typescript/hooks/useCarouselController.d.ts +2 -1
- package/lib/typescript/layouts/BaseLayout.d.ts +2 -2
- package/lib/typescript/layouts/stack.d.ts +1 -1
- package/lib/typescript/types.d.ts +14 -2
- package/lib/typescript/utils/dealWithAnimation.d.ts +2 -0
- package/package.json +12 -2
- package/src/Carousel.tsx +203 -188
- package/src/ScrollViewGesture.tsx +70 -33
- package/src/hooks/useAutoPlay.ts +4 -1
- package/src/hooks/useCarouselController.tsx +28 -12
- package/src/layouts/BaseLayout.tsx +3 -3
- package/src/layouts/stack.ts +1 -1
- package/src/types.ts +22 -4
- package/src/utils/dealWithAnimation.ts +22 -0
package/src/Carousel.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React
|
|
1
|
+
import React from 'react';
|
|
2
2
|
import Animated, { runOnJS, useDerivedValue } from 'react-native-reanimated';
|
|
3
3
|
|
|
4
4
|
import { useCarouselController } from './hooks/useCarouselController';
|
|
@@ -17,199 +17,214 @@ import { CTX } from './store';
|
|
|
17
17
|
import { useCommonVariables } from './hooks/useCommonVariables';
|
|
18
18
|
import { useOnProgressChange } from './hooks/useOnProgressChange';
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
_props
|
|
22
|
-
|
|
23
|
-
) {
|
|
24
|
-
const props = useInitProps(_props);
|
|
25
|
-
|
|
26
|
-
const {
|
|
27
|
-
data,
|
|
28
|
-
rawData,
|
|
29
|
-
loop,
|
|
30
|
-
mode,
|
|
31
|
-
style,
|
|
32
|
-
width,
|
|
33
|
-
height,
|
|
34
|
-
vertical,
|
|
35
|
-
autoPlay,
|
|
36
|
-
windowSize,
|
|
37
|
-
autoPlayReverse,
|
|
38
|
-
autoPlayInterval,
|
|
39
|
-
scrollAnimationDuration,
|
|
40
|
-
renderItem,
|
|
41
|
-
onScrollEnd,
|
|
42
|
-
onSnapToItem,
|
|
43
|
-
onScrollBegin,
|
|
44
|
-
onProgressChange,
|
|
45
|
-
customAnimation,
|
|
46
|
-
} = props;
|
|
47
|
-
|
|
48
|
-
const commonVariables = useCommonVariables(props);
|
|
49
|
-
const { size, handlerOffsetX } = commonVariables;
|
|
50
|
-
|
|
51
|
-
const offsetX = useDerivedValue(() => {
|
|
52
|
-
const totalSize = size * data.length;
|
|
53
|
-
const x = handlerOffsetX.value % totalSize;
|
|
54
|
-
|
|
55
|
-
if (!loop) {
|
|
56
|
-
return handlerOffsetX.value;
|
|
57
|
-
}
|
|
58
|
-
return isNaN(x) ? 0 : x;
|
|
59
|
-
}, [loop, size, data]);
|
|
60
|
-
|
|
61
|
-
usePropsErrorBoundary(props);
|
|
62
|
-
useOnProgressChange({ size, offsetX, rawData, onProgressChange });
|
|
63
|
-
|
|
64
|
-
const carouselController = useCarouselController({
|
|
65
|
-
loop,
|
|
66
|
-
size,
|
|
67
|
-
handlerOffsetX,
|
|
68
|
-
length: data.length,
|
|
69
|
-
disable: !data.length,
|
|
70
|
-
originalLength: data.length,
|
|
71
|
-
onScrollEnd: () => runOnJS(_onScrollEnd)(),
|
|
72
|
-
onScrollBegin: () => !!onScrollBegin && runOnJS(onScrollBegin)(),
|
|
73
|
-
onChange: (i) => !!onSnapToItem && runOnJS(onSnapToItem)(i),
|
|
74
|
-
duration: scrollAnimationDuration,
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
const {
|
|
78
|
-
next,
|
|
79
|
-
prev,
|
|
80
|
-
sharedPreIndex,
|
|
81
|
-
sharedIndex,
|
|
82
|
-
computedIndex,
|
|
83
|
-
getCurrentIndex,
|
|
84
|
-
} = carouselController;
|
|
85
|
-
|
|
86
|
-
const { start, pause } = useAutoPlay({
|
|
87
|
-
autoPlay,
|
|
88
|
-
autoPlayInterval,
|
|
89
|
-
autoPlayReverse,
|
|
90
|
-
carouselController,
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
const scrollViewGestureOnScrollBegin = React.useCallback(() => {
|
|
94
|
-
pause();
|
|
95
|
-
onScrollBegin?.();
|
|
96
|
-
}, [onScrollBegin, pause]);
|
|
97
|
-
|
|
98
|
-
const _onScrollEnd = React.useCallback(() => {
|
|
99
|
-
computedIndex();
|
|
100
|
-
onScrollEnd?.(sharedPreIndex.current, sharedIndex.current);
|
|
101
|
-
}, [sharedPreIndex, sharedIndex, computedIndex, onScrollEnd]);
|
|
102
|
-
|
|
103
|
-
const scrollViewGestureOnScrollEnd = React.useCallback(() => {
|
|
104
|
-
start();
|
|
105
|
-
_onScrollEnd();
|
|
106
|
-
}, [_onScrollEnd, start]);
|
|
107
|
-
|
|
108
|
-
const goToIndex = React.useCallback(
|
|
109
|
-
(i: number, animated?: boolean) => {
|
|
110
|
-
carouselController.to(i, animated);
|
|
111
|
-
},
|
|
112
|
-
[carouselController]
|
|
113
|
-
);
|
|
114
|
-
|
|
115
|
-
React.useImperativeHandle(
|
|
116
|
-
ref,
|
|
117
|
-
() => ({
|
|
118
|
-
next,
|
|
119
|
-
prev,
|
|
120
|
-
getCurrentIndex,
|
|
121
|
-
goToIndex,
|
|
122
|
-
scrollTo: carouselController.scrollTo,
|
|
123
|
-
}),
|
|
124
|
-
[getCurrentIndex, goToIndex, next, prev, carouselController.scrollTo]
|
|
125
|
-
);
|
|
126
|
-
|
|
127
|
-
const visibleRanges = useVisibleRanges({
|
|
128
|
-
total: data.length,
|
|
129
|
-
viewSize: size,
|
|
130
|
-
translation: handlerOffsetX,
|
|
131
|
-
windowSize,
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
const layoutConfig = useLayoutConfig<T>({ ...props, size });
|
|
135
|
-
|
|
136
|
-
const renderLayout = React.useCallback(
|
|
137
|
-
(item: T, i: number) => {
|
|
138
|
-
let realIndex = i;
|
|
139
|
-
if (rawData.length === DATA_LENGTH.SINGLE_ITEM) {
|
|
140
|
-
realIndex = i % 1;
|
|
141
|
-
}
|
|
20
|
+
const Carousel = React.forwardRef<ICarouselInstance, TCarouselProps<any>>(
|
|
21
|
+
(_props, ref) => {
|
|
22
|
+
const props = useInitProps(_props);
|
|
142
23
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
return (
|
|
148
|
-
<BaseLayout
|
|
149
|
-
key={i}
|
|
150
|
-
index={i}
|
|
151
|
-
handlerOffsetX={offsetX}
|
|
152
|
-
visibleRanges={visibleRanges}
|
|
153
|
-
animationStyle={customAnimation || layoutConfig}
|
|
154
|
-
>
|
|
155
|
-
{({ animationValue }) =>
|
|
156
|
-
renderItem({
|
|
157
|
-
item,
|
|
158
|
-
index: realIndex,
|
|
159
|
-
animationValue,
|
|
160
|
-
})
|
|
161
|
-
}
|
|
162
|
-
</BaseLayout>
|
|
163
|
-
);
|
|
164
|
-
},
|
|
165
|
-
[
|
|
24
|
+
const {
|
|
25
|
+
data,
|
|
166
26
|
rawData,
|
|
167
|
-
|
|
168
|
-
|
|
27
|
+
loop,
|
|
28
|
+
mode,
|
|
29
|
+
style,
|
|
30
|
+
width,
|
|
31
|
+
height,
|
|
32
|
+
vertical,
|
|
33
|
+
autoPlay,
|
|
34
|
+
windowSize,
|
|
35
|
+
autoPlayReverse,
|
|
36
|
+
autoPlayInterval,
|
|
37
|
+
scrollAnimationDuration,
|
|
38
|
+
withAnimation,
|
|
169
39
|
renderItem,
|
|
170
|
-
|
|
40
|
+
onScrollEnd,
|
|
41
|
+
onSnapToItem,
|
|
42
|
+
onScrollBegin,
|
|
43
|
+
onProgressChange,
|
|
171
44
|
customAnimation,
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
45
|
+
} = props;
|
|
46
|
+
|
|
47
|
+
const commonVariables = useCommonVariables(props);
|
|
48
|
+
const { size, handlerOffsetX } = commonVariables;
|
|
49
|
+
|
|
50
|
+
const offsetX = useDerivedValue(() => {
|
|
51
|
+
const totalSize = size * data.length;
|
|
52
|
+
const x = handlerOffsetX.value % totalSize;
|
|
53
|
+
|
|
54
|
+
if (!loop) {
|
|
55
|
+
return handlerOffsetX.value;
|
|
56
|
+
}
|
|
57
|
+
return isNaN(x) ? 0 : x;
|
|
58
|
+
}, [loop, size, data]);
|
|
59
|
+
|
|
60
|
+
usePropsErrorBoundary(props);
|
|
61
|
+
useOnProgressChange({ size, offsetX, rawData, onProgressChange });
|
|
62
|
+
|
|
63
|
+
const carouselController = useCarouselController({
|
|
64
|
+
loop,
|
|
65
|
+
size,
|
|
66
|
+
handlerOffsetX,
|
|
67
|
+
length: data.length,
|
|
68
|
+
disable: !data.length,
|
|
69
|
+
withAnimation,
|
|
70
|
+
originalLength: data.length,
|
|
71
|
+
onScrollEnd: () => runOnJS(_onScrollEnd)(),
|
|
72
|
+
onScrollBegin: () => !!onScrollBegin && runOnJS(onScrollBegin)(),
|
|
73
|
+
onChange: (i) => !!onSnapToItem && runOnJS(onSnapToItem)(i),
|
|
74
|
+
duration: scrollAnimationDuration,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const {
|
|
78
|
+
next,
|
|
79
|
+
prev,
|
|
80
|
+
sharedPreIndex,
|
|
81
|
+
sharedIndex,
|
|
82
|
+
computedIndex,
|
|
83
|
+
getCurrentIndex,
|
|
84
|
+
} = carouselController;
|
|
85
|
+
|
|
86
|
+
const { start, pause } = useAutoPlay({
|
|
87
|
+
autoPlay,
|
|
88
|
+
autoPlayInterval,
|
|
89
|
+
autoPlayReverse,
|
|
90
|
+
carouselController,
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const _onScrollEnd = React.useCallback(() => {
|
|
94
|
+
computedIndex();
|
|
95
|
+
onScrollEnd?.(sharedPreIndex.current, sharedIndex.current);
|
|
96
|
+
}, [sharedPreIndex, sharedIndex, computedIndex, onScrollEnd]);
|
|
97
|
+
|
|
98
|
+
const scrollViewGestureOnScrollBegin = React.useCallback(() => {
|
|
99
|
+
pause();
|
|
100
|
+
onScrollBegin?.();
|
|
101
|
+
}, [onScrollBegin, pause]);
|
|
102
|
+
|
|
103
|
+
const scrollViewGestureOnScrollEnd = React.useCallback(() => {
|
|
104
|
+
start();
|
|
105
|
+
_onScrollEnd();
|
|
106
|
+
}, [_onScrollEnd, start]);
|
|
107
|
+
|
|
108
|
+
const scrollViewGestureOnTouchBegin = React.useCallback(pause, [pause]);
|
|
109
|
+
|
|
110
|
+
const scrollViewGestureOnTouchEnd = React.useCallback(start, [start]);
|
|
111
|
+
|
|
112
|
+
const goToIndex = React.useCallback(
|
|
113
|
+
(i: number, animated?: boolean) => {
|
|
114
|
+
carouselController.to(i, animated);
|
|
115
|
+
},
|
|
116
|
+
[carouselController]
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
React.useImperativeHandle(
|
|
120
|
+
ref,
|
|
121
|
+
() => ({
|
|
122
|
+
next,
|
|
123
|
+
prev,
|
|
124
|
+
getCurrentIndex,
|
|
125
|
+
goToIndex,
|
|
126
|
+
scrollTo: carouselController.scrollTo,
|
|
127
|
+
}),
|
|
128
|
+
[
|
|
129
|
+
getCurrentIndex,
|
|
130
|
+
goToIndex,
|
|
131
|
+
next,
|
|
132
|
+
prev,
|
|
133
|
+
carouselController.scrollTo,
|
|
134
|
+
]
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
const visibleRanges = useVisibleRanges({
|
|
138
|
+
total: data.length,
|
|
139
|
+
viewSize: size,
|
|
140
|
+
translation: handlerOffsetX,
|
|
141
|
+
windowSize,
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const layoutConfig = useLayoutConfig({ ...props, size });
|
|
145
|
+
|
|
146
|
+
const renderLayout = React.useCallback(
|
|
147
|
+
(item: any, i: number) => {
|
|
148
|
+
let realIndex = i;
|
|
149
|
+
if (rawData.length === DATA_LENGTH.SINGLE_ITEM) {
|
|
150
|
+
realIndex = i % 1;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (rawData.length === DATA_LENGTH.DOUBLE_ITEM) {
|
|
154
|
+
realIndex = i % 2;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return (
|
|
158
|
+
<BaseLayout
|
|
159
|
+
key={i}
|
|
160
|
+
index={i}
|
|
161
|
+
handlerOffsetX={offsetX}
|
|
162
|
+
visibleRanges={visibleRanges}
|
|
163
|
+
animationStyle={customAnimation || layoutConfig}
|
|
164
|
+
>
|
|
165
|
+
{({ animationValue }) =>
|
|
166
|
+
renderItem({
|
|
167
|
+
item,
|
|
168
|
+
index: realIndex,
|
|
169
|
+
animationValue,
|
|
170
|
+
})
|
|
171
|
+
}
|
|
172
|
+
</BaseLayout>
|
|
173
|
+
);
|
|
174
|
+
},
|
|
175
|
+
[
|
|
176
|
+
rawData,
|
|
177
|
+
offsetX,
|
|
178
|
+
visibleRanges,
|
|
179
|
+
renderItem,
|
|
180
|
+
layoutConfig,
|
|
181
|
+
customAnimation,
|
|
182
|
+
]
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
return (
|
|
186
|
+
<CTX.Provider value={{ props, common: commonVariables }}>
|
|
187
|
+
<View
|
|
188
|
+
style={[
|
|
189
|
+
styles.container,
|
|
190
|
+
{ width: width || '100%', height: height || '100%' },
|
|
191
|
+
style,
|
|
192
|
+
]}
|
|
189
193
|
>
|
|
190
|
-
<
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
},
|
|
198
|
-
style,
|
|
199
|
-
vertical
|
|
200
|
-
? styles.itemsVertical
|
|
201
|
-
: styles.itemsHorizontal,
|
|
202
|
-
]}
|
|
194
|
+
<ScrollViewGesture
|
|
195
|
+
size={size}
|
|
196
|
+
translation={handlerOffsetX}
|
|
197
|
+
onScrollBegin={scrollViewGestureOnScrollBegin}
|
|
198
|
+
onScrollEnd={scrollViewGestureOnScrollEnd}
|
|
199
|
+
onTouchBegin={scrollViewGestureOnTouchBegin}
|
|
200
|
+
onTouchEnd={scrollViewGestureOnTouchEnd}
|
|
203
201
|
>
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
202
|
+
<Animated.View
|
|
203
|
+
key={mode}
|
|
204
|
+
style={[
|
|
205
|
+
styles.container,
|
|
206
|
+
{
|
|
207
|
+
width: width || '100%',
|
|
208
|
+
height: height || '100%',
|
|
209
|
+
},
|
|
210
|
+
style,
|
|
211
|
+
vertical
|
|
212
|
+
? styles.itemsVertical
|
|
213
|
+
: styles.itemsHorizontal,
|
|
214
|
+
]}
|
|
215
|
+
>
|
|
216
|
+
{data.map(renderLayout)}
|
|
217
|
+
</Animated.View>
|
|
218
|
+
</ScrollViewGesture>
|
|
219
|
+
</View>
|
|
220
|
+
</CTX.Provider>
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
);
|
|
224
|
+
|
|
225
|
+
export default Carousel as <T extends any>(
|
|
226
|
+
props: React.PropsWithChildren<TCarouselProps<T>>
|
|
227
|
+
) => React.ReactElement;
|
|
213
228
|
|
|
214
229
|
const styles = StyleSheet.create({
|
|
215
230
|
container: {
|
|
@@ -12,10 +12,11 @@ import Animated, {
|
|
|
12
12
|
useDerivedValue,
|
|
13
13
|
useSharedValue,
|
|
14
14
|
withDecay,
|
|
15
|
-
withTiming,
|
|
16
15
|
} from 'react-native-reanimated';
|
|
17
16
|
import { Easing } from './constants';
|
|
18
17
|
import { CTX } from './store';
|
|
18
|
+
import type { WithAnimation } from './types';
|
|
19
|
+
import { dealWithAnimation } from './utils/dealWithAnimation';
|
|
19
20
|
|
|
20
21
|
type GestureContext = {
|
|
21
22
|
panOffset: number;
|
|
@@ -25,8 +26,10 @@ type GestureContext = {
|
|
|
25
26
|
interface Props {
|
|
26
27
|
size: number;
|
|
27
28
|
infinite?: boolean;
|
|
28
|
-
onScrollEnd?: () => void;
|
|
29
29
|
onScrollBegin?: () => void;
|
|
30
|
+
onScrollEnd?: () => void;
|
|
31
|
+
onTouchBegin?: () => void;
|
|
32
|
+
onTouchEnd?: () => void;
|
|
30
33
|
style?: StyleProp<ViewStyle>;
|
|
31
34
|
translation: Animated.SharedValue<number>;
|
|
32
35
|
}
|
|
@@ -42,10 +45,18 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
|
|
|
42
45
|
panGestureHandlerProps,
|
|
43
46
|
loop: infinite,
|
|
44
47
|
scrollAnimationDuration,
|
|
48
|
+
withAnimation,
|
|
45
49
|
},
|
|
46
50
|
} = React.useContext(CTX);
|
|
47
51
|
|
|
48
|
-
const {
|
|
52
|
+
const {
|
|
53
|
+
translation,
|
|
54
|
+
size,
|
|
55
|
+
onScrollBegin,
|
|
56
|
+
onScrollEnd,
|
|
57
|
+
onTouchBegin,
|
|
58
|
+
onTouchEnd,
|
|
59
|
+
} = props;
|
|
49
60
|
|
|
50
61
|
const maxPage = data.length;
|
|
51
62
|
const isHorizontal = useDerivedValue(() => !vertical, [vertical]);
|
|
@@ -56,20 +67,27 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
|
|
|
56
67
|
const _withSpring = React.useCallback(
|
|
57
68
|
(toValue: number, onFinished?: () => void) => {
|
|
58
69
|
'worklet';
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
{
|
|
70
|
+
const callback = (isFinished: boolean) => {
|
|
71
|
+
'worklet';
|
|
72
|
+
if (isFinished) {
|
|
73
|
+
onFinished && runOnJS(onFinished)();
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const defaultWithAnimation: WithAnimation = {
|
|
78
|
+
type: 'timing',
|
|
79
|
+
config: {
|
|
62
80
|
duration: scrollAnimationDuration,
|
|
63
81
|
easing: Easing.easeOutQuart,
|
|
64
82
|
},
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
return dealWithAnimation(withAnimation ?? defaultWithAnimation)(
|
|
86
|
+
toValue,
|
|
87
|
+
callback
|
|
70
88
|
);
|
|
71
89
|
},
|
|
72
|
-
[scrollAnimationDuration]
|
|
90
|
+
[scrollAnimationDuration, withAnimation]
|
|
73
91
|
);
|
|
74
92
|
|
|
75
93
|
const endWithSpring = React.useCallback(
|
|
@@ -116,22 +134,28 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
|
|
|
116
134
|
]
|
|
117
135
|
);
|
|
118
136
|
|
|
119
|
-
const
|
|
120
|
-
|
|
121
|
-
|
|
137
|
+
const onFinish = React.useCallback(
|
|
138
|
+
(isFinished: boolean) => {
|
|
139
|
+
'worklet';
|
|
122
140
|
if (isFinished) {
|
|
123
141
|
touching.value = false;
|
|
124
142
|
onScrollEnd && runOnJS(onScrollEnd)();
|
|
125
143
|
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
144
|
+
},
|
|
145
|
+
[onScrollEnd, touching]
|
|
146
|
+
);
|
|
147
|
+
|
|
148
|
+
const activeDecay = React.useCallback(() => {
|
|
149
|
+
'worklet';
|
|
150
|
+
touching.value = true;
|
|
151
|
+
translation.value = withDecay(
|
|
152
|
+
{ velocity: scrollEndVelocity.value },
|
|
153
|
+
(isFinished) => onFinish(isFinished as boolean)
|
|
154
|
+
);
|
|
155
|
+
}, [onFinish, scrollEndVelocity.value, touching, translation]);
|
|
134
156
|
|
|
157
|
+
const resetBoundary = React.useCallback(() => {
|
|
158
|
+
'worklet';
|
|
135
159
|
if (touching.value) {
|
|
136
160
|
return;
|
|
137
161
|
}
|
|
@@ -158,15 +182,14 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
|
|
|
158
182
|
}
|
|
159
183
|
}
|
|
160
184
|
}, [
|
|
161
|
-
|
|
162
|
-
touching,
|
|
163
|
-
_withSpring,
|
|
185
|
+
touching.value,
|
|
164
186
|
translation,
|
|
165
|
-
scrollEndTranslation,
|
|
166
|
-
scrollEndVelocity,
|
|
167
|
-
onScrollEnd,
|
|
168
187
|
maxPage,
|
|
169
188
|
size,
|
|
189
|
+
scrollEndTranslation.value,
|
|
190
|
+
infinite,
|
|
191
|
+
activeDecay,
|
|
192
|
+
_withSpring,
|
|
170
193
|
]);
|
|
171
194
|
|
|
172
195
|
useAnimatedReaction(
|
|
@@ -176,7 +199,7 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
|
|
|
176
199
|
resetBoundary();
|
|
177
200
|
}
|
|
178
201
|
},
|
|
179
|
-
[pagingEnabled]
|
|
202
|
+
[pagingEnabled, resetBoundary]
|
|
180
203
|
);
|
|
181
204
|
|
|
182
205
|
const panGestureEventHandler = useAnimatedGestureHandler<
|
|
@@ -220,14 +243,24 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
|
|
|
220
243
|
? translationX
|
|
221
244
|
: translationY;
|
|
222
245
|
|
|
223
|
-
endWithSpring(() => onScrollEnd && runOnJS(onScrollEnd)());
|
|
246
|
+
// endWithSpring(() => onScrollEnd && runOnJS(onScrollEnd)());
|
|
247
|
+
endWithSpring(onScrollEnd);
|
|
224
248
|
|
|
225
249
|
if (!infinite) {
|
|
226
250
|
touching.value = false;
|
|
227
251
|
}
|
|
228
252
|
},
|
|
229
253
|
},
|
|
230
|
-
[
|
|
254
|
+
[
|
|
255
|
+
pagingEnabled,
|
|
256
|
+
isHorizontal.value,
|
|
257
|
+
infinite,
|
|
258
|
+
maxPage,
|
|
259
|
+
size,
|
|
260
|
+
enableSnap,
|
|
261
|
+
onScrollBegin,
|
|
262
|
+
onScrollEnd,
|
|
263
|
+
]
|
|
231
264
|
);
|
|
232
265
|
|
|
233
266
|
const directionStyle = React.useMemo(() => {
|
|
@@ -235,7 +268,11 @@ const IScrollViewGesture: React.FC<Props> = (props) => {
|
|
|
235
268
|
}, [vertical]);
|
|
236
269
|
|
|
237
270
|
return (
|
|
238
|
-
<Animated.View
|
|
271
|
+
<Animated.View
|
|
272
|
+
style={[styles.container, directionStyle, style]}
|
|
273
|
+
onTouchStart={onTouchBegin}
|
|
274
|
+
onTouchEnd={onTouchEnd}
|
|
275
|
+
>
|
|
239
276
|
<PanGestureHandler
|
|
240
277
|
{...panGestureHandlerProps}
|
|
241
278
|
onGestureEvent={panGestureEventHandler}
|
package/src/hooks/useAutoPlay.ts
CHANGED
|
@@ -30,9 +30,12 @@ export function useAutoPlay(opts: {
|
|
|
30
30
|
}, [autoPlayReverse, autoPlayInterval, carouselController]);
|
|
31
31
|
|
|
32
32
|
const pause = React.useCallback(() => {
|
|
33
|
+
if (!autoPlay) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
33
36
|
timer.current && clearInterval(timer.current);
|
|
34
37
|
stopped.current = true;
|
|
35
|
-
}, []);
|
|
38
|
+
}, [autoPlay]);
|
|
36
39
|
|
|
37
40
|
const start = React.useCallback(() => {
|
|
38
41
|
if (!autoPlay) {
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type Animated from 'react-native-reanimated';
|
|
3
3
|
import { Easing } from '../constants';
|
|
4
|
-
import { runOnJS, useSharedValue
|
|
5
|
-
import type {
|
|
4
|
+
import { runOnJS, useSharedValue } from 'react-native-reanimated';
|
|
5
|
+
import type {
|
|
6
|
+
TCarouselActionOptions,
|
|
7
|
+
TCarouselProps,
|
|
8
|
+
WithAnimation,
|
|
9
|
+
} from '../types';
|
|
10
|
+
import { dealWithAnimation } from '@/utils/dealWithAnimation';
|
|
6
11
|
|
|
7
12
|
interface IOpts {
|
|
8
13
|
loop: boolean;
|
|
9
14
|
size: number;
|
|
10
15
|
handlerOffsetX: Animated.SharedValue<number>;
|
|
16
|
+
withAnimation?: TCarouselProps['withAnimation'];
|
|
11
17
|
disable?: boolean;
|
|
12
18
|
duration?: number;
|
|
13
19
|
originalLength: number;
|
|
@@ -36,6 +42,7 @@ export function useCarouselController(options: IOpts): ICarouselController {
|
|
|
36
42
|
size,
|
|
37
43
|
loop,
|
|
38
44
|
handlerOffsetX,
|
|
45
|
+
withAnimation,
|
|
39
46
|
disable = false,
|
|
40
47
|
originalLength,
|
|
41
48
|
length,
|
|
@@ -116,22 +123,31 @@ export function useCarouselController(options: IOpts): ICarouselController {
|
|
|
116
123
|
|
|
117
124
|
const scrollWithTiming = React.useCallback(
|
|
118
125
|
(toValue: number, onFinished?: () => void) => {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
(isFinished
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
onFinished && runOnJS(onFinished)();
|
|
126
|
-
}
|
|
126
|
+
'worklet';
|
|
127
|
+
const callback = (isFinished: boolean) => {
|
|
128
|
+
'worklet';
|
|
129
|
+
if (isFinished) {
|
|
130
|
+
runOnJS(onScrollEnd)();
|
|
131
|
+
onFinished && runOnJS(onFinished)();
|
|
127
132
|
}
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const defaultWithAnimation: WithAnimation = {
|
|
136
|
+
type: 'timing',
|
|
137
|
+
config: { duration, easing: Easing.easeOutQuart },
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
return dealWithAnimation(withAnimation ?? defaultWithAnimation)(
|
|
141
|
+
toValue,
|
|
142
|
+
callback
|
|
128
143
|
);
|
|
129
144
|
},
|
|
130
|
-
[
|
|
145
|
+
[duration, withAnimation, onScrollEnd]
|
|
131
146
|
);
|
|
132
147
|
|
|
133
148
|
const next = React.useCallback(
|
|
134
149
|
(opts: TCarouselActionOptions = {}) => {
|
|
150
|
+
'worklet';
|
|
135
151
|
const { count = 1, animated = true, onFinished } = opts;
|
|
136
152
|
if (!canSliding() || (!loop && index.value >= length - 1)) return;
|
|
137
153
|
|
|
@@ -144,7 +160,7 @@ export function useCarouselController(options: IOpts): ICarouselController {
|
|
|
144
160
|
handlerOffsetX.value = scrollWithTiming(
|
|
145
161
|
-nextPage * size,
|
|
146
162
|
onFinished
|
|
147
|
-
);
|
|
163
|
+
) as any;
|
|
148
164
|
} else {
|
|
149
165
|
handlerOffsetX.value = -nextPage * size;
|
|
150
166
|
onFinished?.();
|